2

共有メモリを使用して共通データを共有する複数のタスクで構成されるアプリケーションがあります。これまで、共有メモリ内のデータは次のようになりました。

struct Store = {
    int id;
    Array<Module, 5> modules;
};

ここで、Moduleは次のように定義されます

struct Module = {
    uint32_t a;
    char b[64];
    Array<Component, 10> components;
};

このStore構造は固定サイズであり、共有メモリ内で簡単に使用できます。

しかし今、私は他のモジュールをサポートする必要がModuleAありModuleBます。通常のC++コンテキスト内では、これらを次のようにモデル化します。

struct ModuleBase {
    // common informations
};
struct ModuleA : public ModuleBase {
    // ...
};
struct ModuleB : public ModuleBase {
    // ...
};

Moduleで置き換えModule*ますStore

しかし、共有メモリ内では、これはそれほど簡単ではありません。共有メモリ内のデータへのアクセスは、構造を修正するために簡単です。そのため、コンパイル時の配列が使用されます。このプロパティを別のモジュールで使用したいと思います。

アイデア1

union Module {
    ModuleType type;
    ModuleA moduleA;
    ModuleB moduleB;
};

問題は、私のModuleクラスにコンストラクターがあり、それが内で許可されていないことunionです。アクセスは、を使用して簡単typeModule.moduleX 修正できます。コンストラクターの必要性を排除します。

アイデア2

特定のクラスの最大サイズを評価するテンプレートを使用します。例:

const size_t max_module_size = MaxTMP<ModuleA, ModuleB>::value;

これは、モジュールを格納するために必要なバッファーのサイズです。

char ModuleBuffer[max_module_size];

(多分、ModuleBufferで使用するために、構造体にカプセル化する必要がありますArray

アクセスには注意が必要です。のコンテンツは、ModuleBufferにキャストする必要がModuleBaseあります。それは私がいくつか必要だと思います。また、に入れるために何らかの方法で「ModuleX」をキャストする必要があります。typeModuleXreinterpret_castModuleBuffer

質問

私は両方のアイデアが好きではありませんが、この問題を処理する別の方法を想像することはできません。コメントや、さらに良い解決策はありますか?

4

1 に答える 1

2

事実上、あなたは岩と固い場所の間にいます。

付属の設備があるので、試してみboost::variantます。そうでなければ、同様のものを再現するのはそれほど難しくありませんが、長いです...


サイズに加えて、アライメントにも注意する必要があります。ここでは C++11 を使用すると便利ですが、いくつかのライブラリ/拡張機能を使用して C++03 でこれを作成することもできます。

unionaはそれほど特別なものではないことに注意してください。独自の方法で簡単に実装できboost::variant、「タグ付け」することもできます。

いくつかのヘルパーが役に立ちます:

/// Size and Alignment utilties
constexpr size_t max(size_t t) { return t; }

template <typename... U>
constexpr size_t max(size_t l, size_t r, U... tail) {
    return l > max(r, tail...) ? l : max(r, tail...);
}

template <typename... T>
struct size { static size_t const value = max(sizeof(T)...); };

template <typename... T>
struct alignment { static size_t const value = max(alignof(T)...); };


/// Position of a type in the list
template <typename...> struct position;

template <typename T>
struct position<T> {
    static size_t const value = 0;
};

template <typename T, typename Head, typename... Tail>
struct position<T, Head, Tail...> {
    static size_t const value =
        std::is_same<T, Head>::value ? 0 : 1 + position<T, Tail...>::value;
};


/// Type at a given position
template <size_t, typename...> struct at;

template <size_t N, typename T, typename... Tail>
struct at<N, T, Tail...> { typedef typename at<N-1, Tail..>::type type; };

template <typename T, typename... Tail>
struct at<0, T, Tail...> { typedef T type; };

ここから真のお楽しみが始まります: 実行時に変更される可能性のある型を使用して、タイプセーフな方法で関数を適用する方法 :x ?

/// Function application
template <typename...> struct Apply;

template <typename H, typename... Tail>
struct Apply<H, Tail...> {
    // Mutable
    template <typename Func>
    static void Do(Func& f, void* storage, size_t tag) {
         if (tag == 0) { f(*reinterpret_cast<H*>(storage)); }
         else { Apply<Tail...>::Do(f, storage, tag-1); }
    }
    template <typename Func>
    static void Do(Func const& f, void* storage, size_t tag) {
         if (tag == 0) { f(*reinterpret_cast<H*>(storage)); }
         else { Apply<Tail...>::Do(f, storage, tag-1); }
    }

    // Const
    template <typename Func>
    static void Do(Func& f, void const* storage, size_t tag) {
         if (tag == 0) { f(*reinterpret_cast<H const*>(storage)); }
         else { Apply<Tail...>::Do(f, storage, tag-1); }
    }
    template <typename Func>
    static void Do(Func const& f, void const* storage, size_t tag) {
         if (tag == 0) { f(*reinterpret_cast<H const*>(storage)); }
         else { Apply<Tail...>::Do(f, storage, tag-1); }
    }
}; // struct Apply

/// We need recursion to end quietly even though `tag` is a runtime argument
/// we place the precondition that `tag` should be a valid index in the type
/// list so this should never be reached.
template <>
struct Apply<> {
    template <typename... T>
    static void Do(T...&&) { abort(); }
}; // struct Apply

これを使用して、タイプ セーフな方法で動的にディスパッチできます。

/// Variant itself
template <typename... List>
class Variant {
public:
    /// Constructor & co
    Variant() {
        typedef typename at<0, List...>::type First;
        new (&_storage) First();
    }

    Variant(Variant const& other) {
        this->initialize(other);
    }

    Variant& operator=(Variant const& other) {
        this->destroy();
        this->initialize(other);
        return *this;
    }

    ~Variant() { this->destroy(); }

    /// Conversions
    template <typename T>
    explicit Variant(T const& t) {
        _tag = position<T, List...>::value;
        new (&_storage) T(t);
    }

    template <typename T>
    Variant& operator=(T const& t) {
        _tag = position<T, List...>::value;
        this->destroy();
        new (&_storage) T(t);
        return *this;
    }

    /// Applying a func
    template <typename Func>
    void apply(Func& f) { Apply<List...>::Do(f, &_storage, _tag); }

    template <typename Func>
    void apply(Func& f) const { Apply<List...>::Do(f, &_storage, _tag); }

    template <typename Func>
    void apply(Func const& f) { Apply<List...>::Do(f, &_storage, _tag); }

    template <typename Func>
    void apply(Func const& f) const { Apply<List...>::Do(f, &_storage, _tag); }

private:
    void initialize(Variant const& v) {
        struct {
            template <typename T>
            void operator()(T& t) const { new (_storage) T(t); }
            void* _storage;
        } copier = { &_storage };

        v.apply(copier);
        _tag = v._tag;
    }

    void destroy() {
        struct {
            template <typename T>
            void operator()(T& t) const { t.~T(); }
        } eraser;

        this->apply(eraser);
    }

    std::aligned_storage<size<List...>::value,
                         alignment<List...>::value> _storage;
    size_t _tag;
}; // class Variant

私は簡単に言いましたか?

まあ、まだ微妙な問題があります:operator=実装は例外安全ではありません。あなたの場合、これらのタイプには動的メモリ割り当てがないため、問題にはなりません。

参考文献:

于 2012-04-14T15:59:28.583 に答える