7

私がクラスBaseとを持っているとしましょうDerived : public Base。boost::interprocessライブラリを使用して共有メモリセグメントを構築しました。これに似たコードを持つことは可能ですか?

Base* b = new Derived(); 
write(b); //one app writes
Base* b2 = read(b); //second app reads
//b equals b2 (bitwise, not the ptr location)

ここで私が見ている問題は、たとえば、Baseの派生クラスに必要なスペースが不明であるということです(つまり、どのくらいのshmemを割り当てるのですか?)

Q:アプリケーション間でポインタを介してオブジェクトを渡す方法は?

4

5 に答える 5

13

そのドキュメントを読むだけ

特に:

仮想性は禁止されています

仮想テーブルポインタと仮想テーブルは、オブジェクトを構築するプロセスのアドレス空間にあるため、仮想関数または仮想基本クラスを持つクラスを配置すると、共有メモリに配置された仮想ポインタは他のプロセスでは無効になります。彼らはクラッシュします。

各プロセスには異なる仮想テーブルポインタが必要であり、そのポインタを含むオブジェクトは多くのプロセス間で共有されるため、この問題を解決するのは非常に困難です。マップされた領域をすべてのプロセスで同じアドレスにマップした場合でも、仮想テーブルはすべてのプロセスで異なるアドレスにある可能性があります。プロセス間で共有されるオブジェクトの仮想関数を有効にするには、コンパイラを大幅に変更する必要があり、仮想関数のパフォーマンスが低下します。そのため、Boost.Interprocessには、プロセス間で共有されるマップされた領域で仮想関数と仮想継承をサポートする計画がありません。

于 2012-10-19T07:37:01.000 に答える
4

共有メモリは元々POD構造のみを許可します(基本的に、コンストラクタ/コピーなどがある場合があります...)。

Boost.Interprocess共有メモリセグメントへのオフセットの上にポインタセマンティクスをエミュレートすることにより、バーを上げます。

ただし、仮想ポインターは純粋なデータへのポインターではなく、コードセクションへのポインターです。コードセクションは、あるプロセスから別のプロセスに同じアドレスにマップされるとは限らないため、複雑になります。同じバイナリ)。

つまり...いいえ、仮想ポインタ-ポリモーフィックオブジェクトを共有メモリに保存することはできません。


ただし、多くのC ++実装が仮想ポインタメカニズムの使用を選択したからといって、これがポリモーフィックな動作をする唯一の方法であるとは限りません。たとえば、LLVMとClangでは、閉じた階層に基づいて、仮想ポインター(およびRTTI)なしでポリモーフィズムを取得し、メモリ要件を削減します。これらのオブジェクトは、事実上、共有メモリに保存できます。

したがって、共有メモリと互換性のあるポリモーフィズムを取得する方法:テーブル/関数へのポインタを格納する必要はありませんが、インデックスを格納することはできます。

アイデアの例ですが、おそらく洗練されている可能性があります。

/// In header
#include <cassert>

#include <vector>

template <class, size_t> class BaseT;

class Base {
    template <class, size_t> friend class BaseT;
public:

    int get() const; //     -> Implement: 'int getImpl() const' in Derived

    void set(int i); // = 0 -> Implement: 'void setImpl(int i)' in Derived

private:
    struct VTable {
        typedef int (*Getter)(void const*);
        typedef void (*Setter)(void*, int);

        VTable(): _get(0), _set(0) {}

        Getter _get;
        Setter _set;
    };

    static std::vector<VTable>& VT(); // defined in .cpp

    explicit Base(size_t v): _v(v) {}

    size_t _v;
}; // class Base

template <class Derived, size_t Index>
class BaseT: public Base {
public:
    BaseT(): Base(Index) {
        static bool const _ = Register();
        (void)_;
    }

    // Provide default implementation of getImpl
    int getImpl() const { return 0; }

    // No default implementation setImpl

private:
    static int Get(void const* b) {
        Derived const* d = static_cast<Derived const*>(b);
        return d->getImpl();
    }

    static void Set(void* b, int i) {
        Derived* d = static_cast<Derived*>(b);
        d->setImpl(i);
    }

    static bool Register() {
        typedef Base::VTable VTable;

        std::vector<VTable>& vt = Base::VT();

        if (vt.size() <= Index) {
            vt.insert(vt.end(), Index - vt.size() + 1, VTable());
        } else {
            assert(vt[Index]._get == 0 && "Already registered VTable!");
        }

        vt[Index]._get = &Get;
        vt[Index]._set = &Set;
    }
}; // class BaseT

/// In source
std::vector<VTable>& Base::VT() {
    static std::vector<VTable> V;
    return V;
} // Base::VT

int Base::get() const {
    return VT()[_v]._get(this);
} // Base::get

void Base::set(int i) {
    return VT()[_v]._set(this, i);
} // Base::set

わかりました...コンパイラの魔法に感謝していると思います...

使用法に関しては、幸いなことにはるかに簡単です。

/// Another header
#include <Base.h>

// 4 must be unique within the hierarchy
class Derived: public BaseT<Derived, 4> {
     template <class, size_t> friend class BaseT;
public:
    Derived(): _i(0) {}

private:
    int getImpl() const { return _i; }

    void setImpl(int i) { _i = i; }

    int _i;
}; // class Derived

ideoneで動作中。

于 2012-10-19T08:33:40.460 に答える
3

オブジェクトのシリアル化を検討していると思います。http://www.boost.org/doc/libs/1_51_0/libs/serialization/doc/index.htmlをご覧ください

実行できるいくつかの方法は次のとおりです。1。C++クラスをシリアル化する2.別のアプリにデータを送信する3.C++クラスに逆シリアル化する。

于 2012-10-19T07:41:04.820 に答える
-1
//From the example above , I have removed VTable 
// I also removed static variables as per boost::interprocess 
// static variable don't work with shared memory, and also I did not see
// any advantage in actually builting a VTable for all derived classes
#include <vector>
#include <boost/bind.hpp>
#include <boost/function.hpp>

template <class> class BaseT;

class Base {
    template <class> friend class BaseT;
    boost::function< int (void) > _get;
    boost::function< void (int) > _set;
public:

    int get() {
        return _get();
    } //     -> Implement: 'int get() ' in Derived

    void set(int i) {
        _set(i);
    } // = 0 -> Implement: 'void set(int i)' in Derived
}; // class Base

template <class Derived>
class BaseT : public Base {

public:
    BaseT() : Base(), impl(static_cast<Derived *> (this)) {
        Base::_get = boost::bind(&BaseT<Derived>::get, this);
        Base::_set = boost::bind(&BaseT<Derived>::set, this, _1);
    }

    int get() {
        return impl->get();
    }

    void set(int i) {
        impl->set(i);
    }

private:
    Derived * impl;
};


//some A  implementation of Base
struct A : BaseT<A> {

    int get() {
        return 101; //testing implementation
    }

    void set(int i) {
        ; //implementation goes here
    }
};

//some B  implementation of Base
struct B : BaseT<B> {

    int get() {
        return 102; //testing implementation 
    }

    void set(int i) {
        ; //implementation goes here
    }
};

int main() {
    BaseT<A> objectA;
    BaseT<B> objectB;
    Base *a = &objectA;
    Base *b = &objectB;
    std::cout << a->get() << " returned from A class , "
            << b->get() << " returned from B class " << std::endl;
    return 0;
}
于 2013-04-10T00:55:24.670 に答える
-1
//While redefining I changed semantics of constnance in getter, 
//and had non-    const Derived pointer used for both getter and setter. 
//But original simantics can be preserved as following:

    int get() const {
         //return impl->get();
        //this enforces that get has to be const
        static_cast<const Derived *> (this)->get() ;
    }
于 2013-04-10T02:10:48.963 に答える