共享內存最初只允許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。
偉大的,正是我的預期。謝謝! – Queequeg
@Queequeg:有趣的是,我看到使用帶有多態對象的共享內存的命名段。在這種特殊情況下,單個進程訪問該段(同時)並使用共享內存段,以便在進程崩潰時重新啓動後可以找回所有狀態。它涉及重寫所有虛擬指針,所以它肯定涉及。 –