Boost C++ 库

...世界上最受尊敬和专家设计的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ 编码标准

PrevUpHomeNext

映射地址无关指针:offset_ptr

当创建共享内存和内存映射文件以实现两个进程通信时,内存段可以在每个进程中映射到不同的地址。

#include<boost/interprocess/shared_memory_object.hpp>

// ...

using boost::interprocess;

//Open a shared memory segment
shared_memory_object shm_obj
   (open_only                    //open or create
   ,"shared_memory"              //name
   ,read_only   //read-only mode
   );

//Map the whole shared memory
mapped_region region
   ( shm                         //Memory-mappable object
   , read_write                  //Access mode
   );

//This address can be different in each process
void *addr = region.get_address();

这使得在映射区域中创建复杂对象变得困难:放置在映射区域中的 C++ 类实例可能具有指向也放置在映射区域中的另一个对象的指针。由于指针存储的是绝对地址,因此该地址仅对放置该对象的进程有效,除非所有进程都将映射区域映射到相同的地址。

为了能够在映射区域中模拟指针,用户必须使用偏移量(对象之间的距离)而不是绝对地址。映射区域中两个对象之间的偏移量对于映射该区域的任何进程都是相同的,即使该区域位于不同的基址中。为了方便使用偏移量,Boost.Interprocess 提供了 offset_ptr

offset_ptr 封装了提供类似指针接口所需的所有后台操作。该类接口的灵感来自 Boost 智能指针,并且此智能指针存储指向对象的地址与其自身 this 指针之间的偏移量(以字节为单位)。想象一下在常见的 32 位处理器中的一个结构体

struct structure
{
   int               integer1;   //The compiler places this at offset 0 in the structure
   offset_ptr<int>   ptr;        //The compiler places this at offset 4 in the structure
   int               integer2;   //The compiler places this at offset 8 in the structure
};

//...

structure s;

//Assign the address of "integer1" to "ptr".
//"ptr" will store internally "-4":
//    (char*)&s.integer1 - (char*)&s.ptr;
s.ptr = &s.integer1;

//Assign the address of "integer2" to "ptr".
//"ptr" will store internally "4":
//    (char*)&s.integer2 - (char*)&s.ptr;
s.ptr = &s.integer2;

offset_ptr 的一大问题是空指针的表示。空指针不能像偏移量一样安全地表示,因为绝对地址 0 始终位于映射区域之外。由于段可以在每个进程中映射到不同的基址,因此地址 0 和 offset_ptr 之间的距离对于每个进程都是不同的。

一些实现选择偏移量 0(即指向自身的 offset_ptr)作为空指针表示,但这对于许多用例无效,因为很多时候像链表或 STL 容器中的节点之类的结构会指向自身(例如,空容器中的末尾节点),并且需要 0 偏移值。另一种方法是除了偏移量之外,还存储一个布尔值来指示指针是否为空。但是,这会增加指针的大小并降低性能。

因此,offset_ptr 将偏移量 1 定义为空指针,这意味着此类不能指向其自身 this 指针之后的字节。

using namespace boost::interprocess;

offset_ptr<char> ptr;

//Pointing to the next byte of it's own address
//marks the smart pointer as null.
ptr = (char*)&ptr + 1;

//ptr is equal to null
assert(!ptr);

//This is the same as assigning the null value...
ptr = 0;

//ptr is also equal to null
assert(!ptr);

在实践中,此限制并不重要,因为用户几乎从不想指向此地址。

offset_ptr 提供了所有类似指针的操作和 random_access_iterator 类型定义,因此它可以在需要随机访问迭代器的 STL 算法中使用,并通过 traits 检测。有关该类成员和操作的更多信息,请参阅 offset_ptr 参考


PrevUpHomeNext