C++ new placement语法

今天在学习boost的共享内存时,看网上的一段代码。主要实现的功能是一个进程写一份跟踪数据至共享内存缓存区,另一个进程一个接一个打印出来。第一个进程写跟踪数据,然后等待,直到另一个进程打印这份数据。为达到此目的,我们可以使用两个条件变量:第一个用于阻塞发送者直到第二个进程打印出此消息,第二个用于阻塞接受者直到缓存区中有数据供打印。

但是,下面的代码让我感到很是困惑:

//Map the whole shared memory in this process
mapped_region region
    (shm                       //What to map
     ,read_write //Map it as read-write
     );
 
//Get the address of the mapped region
void * addr       = region.get_address();
 
//Construct the shared structure in memory
trace_queue * data = new (addr) trace_queue;

其中trace_queue是一个结构体,也就是我们共享内存中存放的东西。其中,addr是结构体trace_queue已申请的地址。第一次看到这个表达很是不解,通常如果我们要获得一个结构体的指针,应该用下面的方式来申请:

trace_queue * data = new trace_queue;
我还用如下我所能理解的代码来替换上述写法

void *addr = region.get_address();

//Construct the shared structure in memory
trace_queue * data = static_cast<trace_queue *> (addr);

这个逻辑很容易理解,通过static_cast将指向申请的共享内存地址的指针强制转换为指向trace_queue结构体的指针。

但是执行的时候,打印进程却有segmentation fault的错误。通过gdb调试,找到如下错误信息:

Program received signal SIGSEGV, Segmentation fault.
pthread_cond_signal@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S:69
69		movl	MUTEX_KIND(%rcx), %r11d
这让我感到不解。于是我就上网查找如trace_queue * data = new (addr) trace_queue的语法。

原来这是C++的placement new语法。placement new允许你在已经获得的内存上构造一个对象。你可能这样做是出于优化的目的(你需要重新多次构造一个对象)这比每次都要重新申请内存来说会快很多。

此文提到:标准C++也支持placement new操作符,用来在一个预先申请的buffer上构造一个对象。这当要建造一个内存池,一个垃圾收集器或者仅仅是性能和执行安全性是至关重要的(没有内存申请失败的危险,因为内存已经申请到了,并且在一个预分配的buffer上构造一个对象更省时间):

char *buf  = new char[sizeof(string)]; // pre-allocated buffer
string *p = new (buf) string("hi");    // placement new
string *q = new string("hi");          // ordinary heap allocation
你可能也想确定在特定至关重要的部分代码中没有申请内存失败的风险(可能你工作在一个和平使者的项目),你那种情况下,有应该就像使用placement new语法了。

那使用了placement new语法,该如何释放内存呢?你不需要释放在内存buffer上的所有的对象。相反,你只需要删除原始buffer即可。你必须直接手动地调用你的类的析构函数。

这里有关于placement delete的说明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值