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.
vĩ đại, chính xác những gì tôi mong đợi. Cảm ơn! – Queequeg
@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. –