2012-10-19 133 views
5

假設我有BaseDerived : 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) 

我在這裏看到的是實例的問題,對於一個派生類基地所需要的空間是未知的(所以多少SHMEM分配?)

Q:如何通過應用程序之間的指針傳遞對象?

回答

10

只要閱讀其documentation

特別是:

虛實禁止

虛擬表指針和虛擬表是在構造對象的進程的地址 空間,所以如果我們將一個 類放在虛擬函數或虛擬基類中,那麼放置在共享內存中的虛擬 指針將對其他進程無效 ,他們會崩潰。

這個問題很難解決,因爲每個進程都需要一個 不同的虛擬表指針,並且包含該指針的對象在多個進程間共享。即使我們將映射的 區域映射到每個進程中的相同地址,虛擬表也可以在每個進程的不同地址中爲 。要爲進程之間共享的對象啓用虛擬功能 ,需要進行深度編譯器更改 並且虛擬功能會遭受性能影響。這就是爲什麼 Boost.Interprocess沒有任何計劃來支持虛擬功能 和進程之間共享映射區域中的虛擬繼承。

+0

偉大的,正是我的預期。謝謝! – Queequeg

+0

@Queequeg:有趣的是,我看到使用帶有多態對象的共享內存的命名段。在這種特殊情況下,單個進程訪問該段(同時)並使用共享內存段,以便在進程崩潰時重新啓動後可以找回所有狀態。它涉及重寫所有虛擬指針,所以它肯定涉及。 –

3

我相信你正在看物體的序列化。看看http://www.boost.org/doc/libs/1_51_0/libs/serialization/doc/index.html

你可以做一些方法是:1。 連載您的C++類 2.發送數據到另一個應用程序 3.反序列化到C++類。

+1

+1!正如Tony Hoare在CSP中所說:*不要通過共享進行交流,要通過交流進行交流。* –

+0

用序列化的好主意,+1 – Queequeg

+0

當然你可以發送派生類。但不是「多態」。 – CashCow

3

共享內存最初只允許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

-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; 
} 
+0

我看到有人用+10表示無法存儲多態類,有人投下我的票。我建議在投票之前把這個「編譯時和運行時多態性用C++」放進google。即使CashCow收到10票,他的聲明只適用於虛擬表 - 運行時多態類的屬性。社區在這些舊時尚解決方案之前走過了一條路,我們已經使用C++ 17。請閱讀原始問題:「是否可以將多態類存儲在共享內存中?」 。它沒有具體說明它是運行時多態還是編譯時多態。 –

-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() ; 
    } 
+0

我看到有人用+10表示不可能存儲多態類,有人投下我的票。我建議在投票之前把這個「編譯時和運行時多態性用C++」放進google。即使CashCow收到10票,他的聲明只適用於虛擬表 - 運行時多態類的屬性。社區在這些舊時尚解決方案之前走過了一條路,我們已經使用C++ 17。 –

相關問題