我需要使用共享内存来进行进程之间的通信,如果我可以将共享内存文件描述符或公共文件描述符的地址分配给指向结构或向量/映射的指针,我就会徘徊?
例如,addr
如果是共享内存的地址
Struct A{...};
A* stru = static_cast<A*>(addr); // is this OK?
答案 0 :(得分:0)
首先,您应该查看Boost.interprocess并使用它。
有关手动方法,请继续阅读。
为此,您的结构必须不能使用任何指针。它也必须没有任何虚函数。如果它只是一个带有非指针数据成员的结构(意味着只是内置类型,没有std::string
或std::vector
或者任何不是普通结构的东西)及其成员函数(如果有的话)只对该数据进行操作而不调用任何非成员函数,那么它应该是安全的。
您需要确保地址正确对齐。您可以使用以下方式明确核对:
#include <cstdint>
#include <cassert>
// ...
assert(reinterpret_cast<std::uintptr_t>(addr) % alignof(A) == 0);
如果您用来创建共享内存的方法允许您以字节为单位指定所需的对齐方式,那么alignof(A)
将为您提供正确的字节数。
内存的大小也必须足够大(必须至少为sizeof(A)
。)
如果它具有兼容的对齐和大小,那么您必须使用placement new在该内存中创建对象:
#include <new>
// ...
auto stru = new(addr) A;
这将在stru
指向的内存中创建对象addr
。
不要在该对象上调用delete
。在通常调用delete
的位置,您应该手动调用析构函数:
stru->~A();
为了使这更容易,您应该将此对象包装在unique_ptr
中,并使用调用析构函数的自定义lambda删除器:
#include <memory>
// ...
auto a_dtor_caller = [](A* obj){ obj->~A(); };
auto stru = std::unique_ptr<A, decltype(a_dtor_caller)>(new(addr) A, a_dtor_caller);
stru
现在是unique_ptr
,当它超出范围时,它管理的A
实例将被正确销毁。
以上只应该进行一次。其他只需要访问该对象的进程应该使用:
A* stru = static_cast<A*>(addr);
不言而喻,他们也不应该delete
对象,也不应该调用它的析构函数。只有管理对象的unique_ptr
才能这样做。
当您即将释放共享内存时,您需要首先销毁该对象。如果您的代码自然不允许unique_ptr
&#34;过期&#34;在释放共享内存之前,必须手动执行以下操作:
stru.reset();
这将破坏对象,stru
现在实际上是nullptr
。
总而言之,我真的推荐使用Boost.interprocess。不易出错。