我可以将文件描述符的地址分配给变量吗?

Can I assign an address of file descriptor to a variable?

我需要使用共享内存来进行进程之间的通信,我徘徊着是否可以将共享内存文件描述符或公共文件描述符的地址分配给指向结构或vector/map的指针?

例如,addr如果共享内存的地址

Struct A{...};
A* stru = static_cast<A*>(addr);   // is this OK?

首先,您可能应该查看 Boost.interprocess 并使用它。

有关手动方法,请继续阅读。

为此,您的结构不得使用任何指针。它也不能有任何虚函数。如果它只是一个具有非指针数据成员的结构(意味着只是内置类型,没有 std::stringstd::vector 或任何不是普通结构的东西)及其成员函数(如果有的话)只对该数据进行操作,不调用任何非成员函数,那么这样做应该是安全的。

您需要确保地址对齐正确。您可以明确检查:

#include <cstdint>
#include <cassert>
// ...

assert(reinterpret_cast<std::uintptr_t>(addr) % alignof(A) == 0);

如果您用来创建共享内存的方法允许您以字节为单位指定所需的对齐方式,那么 alignof(A) 将为您提供正确的字节数。

内存的大小也必须足够大(必须至少sizeof(A)。)

如果它具有兼容的对齐方式和大小,则您必须使用新放置在该内存中创建您的对象:

#include <new>
// ...

auto stru = new(addr) A;

这将在 addr 指向的内存中创建对象 stru

不要对该对象调用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 "expire",那么您必须手动执行此操作:

stru.reset();

这将破坏对象,stru 现在实际上是一个 nullptr

总而言之,我真的很推荐Boost.interprocess。不易出错。