2012-10-19 26 views
5

Giả sử tôi có lớp BaseDerived : public Base. Tôi đã xây dựng một phân đoạn bộ nhớ dùng chung bằng cách sử dụng thư viện boost :: interprocess. Có thể có mã tương tự như sau:Có thể lưu trữ lớp đa hình trong bộ nhớ dùng chung không?

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

Những vấn đề tôi thấy đây là ví dụ rằng không gian cần thiết cho một lớp có nguồn gốc của cơ sở không rõ (vì vậy có bao nhiêu shmem để phân bổ?)

Q: cách chuyển đối tượng qua con trỏ giữa các ứng dụng?

Trả lời

10

Chỉ cần đọc nó documentation

Đặc biệt:

tính ảo cấm

Con trỏ bảng ảo và bảng ảo trong không gian địa chỉ của quá trình xây dựng các đối tượng, vì vậy nếu chúng ta đặt một lớp với một hàm ảo hoặc lớp cơ sở ảo, con trỏ ảo được đặt trong bộ nhớ dùng chung sẽ không hợp lệ cho các quá trình khác và chúng sẽ sụp đổ.

Vấn đề này rất khó giải quyết, vì mỗi quá trình cần một con trỏ bảng ảo khác nhau và đối tượng có chứa con trỏ được chia sẻ qua nhiều quy trình. Ngay cả khi chúng tôi lập bản đồ vùng được ánh xạ trong cùng một địa chỉ trong mọi quy trình, bảng ảo có thể là ở một địa chỉ khác trong mọi quy trình. Để kích hoạt các chức năng ảo cho các đối tượng được chia sẻ giữa các quá trình, các thay đổi biên dịch sâu là cần thiết và các chức năng ảo sẽ bị ảnh hưởng. Đó là lý do tại sao Boost.Interprocess không có bất kỳ kế hoạch nào để hỗ trợ chức năng ảo và thừa kế ảo trong các vùng được ánh xạ được chia sẻ giữa các quy trình.

+0

vĩ đại, chính xác những gì tôi mong đợi. Cảm ơn! – Queequeg

+0

@Queequeg: Thật thú vị, tôi đã thấy sử dụng các phân đoạn có tên của bộ nhớ dùng chung với các đối tượng đa hình. Trong trường hợp cụ thể này, một tiến trình đơn lẻ đã từng truy cập phân đoạn (đồng thời) và phân đoạn bộ nhớ dùng chung được sử dụng sao cho quá trình bị lỗi, khi khởi động lại nó có thể tìm lại tất cả trạng thái của nó. Nó liên quan đến việc viết lại tất cả các con trỏ ảo mặc dù, do đó, nó chắc chắn có liên quan. –

3

Tôi tin rằng bạn đang xem xét tuần tự hóa các đối tượng. Có một cái nhìn tại http://www.boost.org/doc/libs/1_51_0/libs/serialization/doc/index.html

Một vài cách bạn có thể làm là: 1. serialize lớp C++ của bạn 2. gửi dữ liệu đến một ứng dụng 3. deserialize vào ++ lớp C.

+1

+1! Như Tony Hoare đã nói trong CSP: * Đừng giao tiếp bằng cách chia sẻ, chia sẻ bằng cách liên lạc. * –

+0

ý tưởng tốt với serialization, +1 – Queequeg

+0

tất nhiên bạn có thể gửi lớp dẫn xuất. Nhưng không phải là một "đa hình". – CashCow

3

Bộ nhớ chia sẻ ban đầu chỉ cho phép cấu trúc POD (ở tim, chúng có thể có các hàm tạo/sao chép/v.v ...).

Boost.Interprocess tăng thanh bằng cách mô phỏng con trỏ ngữ nghĩa trên đầu các khoảng trống vào phân đoạn bộ nhớ dùng chung. Tuy nhiên, con trỏ ảo không phải là con trỏ đến dữ liệu thuần túy, đó là con trỏ đến phần mã và đó là nơi mọi thứ trở nên phức tạp vì phần mã không nhất thiết được ánh xạ tới cùng một địa chỉ từ quy trình này sang tiến trình khác (ngay cả khi chúng được khởi chạy từ cùng một nhị phân).

Vì vậy, ... không, không thể lưu trữ các đối tượng đa hình ảo trong bộ nhớ dùng chung.


Tuy nhiên, chỉ vì nhiều C triển khai ++ đã chọn để sử dụng một cơ chế ảo-con trỏ không có nghĩa rằng đây là cách duy nhất để có hành vi đa hình. Ví dụ, trong LLVM và Clang họ xây dựng trên các hệ thống phân cấp đóng của họ để có được đa hình mà không có con trỏ ảo (và RTTI) để giảm yêu cầu bộ nhớ. Những đối tượng đó có thể, hiệu quả, được lưu trữ trong bộ nhớ dùng chung.

Vì vậy, làm thế nào để có được đa hình tương thích với bộ nhớ chia sẻ: chúng ta cần không để lưu trữ các con trỏ tới bảng/chức năng, tuy nhiên chúng tôi có thể lưu trữ chỉ số.

Ví dụ về ý tưởng, nhưng có thể có thể được tinh chỉnh.

/// 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 

Được rồi ... Tôi đoán rằng bây giờ bạn đánh giá cao sự kỳ diệu của trình biên dịch ...

Về việc sử dụng, đó là may mắn đơn giản hơn nhiều:

/// 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 

Trong hành động ở 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

Tôi thấy ai đó có số 10 đã nói rằng không thể lưu trữ các lớp đa hình và ai đó đã bỏ phiếu cho tôi. Tôi đề nghị trước khi bỏ phiếu xuống đưa vào google này "thời gian biên dịch và đa hình thời gian chạy trong c + +". Mặc dù CashCow nhận được 10 phiếu, tuyên bố của ông chỉ áp dụng cho các bảng ảo - các thuộc tính của các lớp đa hình thời gian chạy. Cộng đồng đã vượt qua những giải pháp thời trang cũ, chúng tôi đã sử dụng C++ 17. Vui lòng đọc câu hỏi gốc: "Có thể lưu trữ lớp đa hình trong bộ nhớ dùng chung không?" . Nó không nói cụ thể nếu đó là đa hình thời gian chạy hoặc tính đa hình thời gian biên dịch. –

-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

Tôi thấy ai đó có số 10 đã nói rằng không thể lưu trữ các lớp đa hình và ai đó đã bỏ phiếu cho tôi. Tôi đề nghị trước khi bỏ phiếu xuống đưa vào google này "thời gian biên dịch và đa hình thời gian chạy trong c + +". Mặc dù CashCow nhận được 10 phiếu, tuyên bố của ông chỉ áp dụng cho các bảng ảo - các thuộc tính của các lớp đa hình thời gian chạy. Cộng đồng đã vượt qua những giải pháp thời trang cũ, chúng tôi đã sử dụng C++ 17. –