placement new和placement delete

      在第五版的《C++ primer》中,定位new(placement new)放在最后一章:特殊工具与技术中介绍,讲的比较简单。而在《effctive C++》中则用了一章的篇幅详细的介绍了“定位new和delete”,其中重点讲了placement new和placement delete的原理。本文参考《effctive C++》给出总结。

      在通常的C++程序中,new和delete表达式总是成对出现,并且分别调用了全局的operator new和operator delete,这两个全局操作符(或者直接理解为全局的函数)的基本形式如下:

                        void * operator new ( std::size_t size) throw ( std::bad_alloc );

                        void operator delete (void * pMemory) throw();

现已知有一个class A,语句A *p = new A;包含两步:1、调用全局的operator new分配空间,operator new的参数值即为sizeof(A),由编译器负责传递(关于对一个类sizeof的结果将在下一篇博客中说明);2、operator new函数内部调用类A的构造函数在分配的空间上构造对象。现在有一个微妙的问题:如果第一步的调用成功,分配了空间,但第二布的调用却抛出异常,那如何回收分配的内存空间呢?注意,这个时候这条语句是没有成功执行的,operator new没能成功返回指向分配的内存空间的指针,也就是说p是无效的,所以程序员没有办法回收这块内存。庆幸的是,C++编译器会自动地调用与operator new形式相对应的operator delete来回收那块空间。

       有了前面的准备后,下面正式介绍placement new,如果operator new接受的参数除了一定会有的那个size_t之外还有其他参数,则称其为placement new。由这个定义可知我们可以重载出很多不同形式的placement new,其中一个特殊的是“接受一个指针指向对象该被构造之处”的placement new,这也是placement new名字的由来:特定位置上的new。其形式如下:

                         void * operator new ( std::size_t, void * ptr ) throw ( );

该版本的placement new已纳入C++标准库,通过#include<new>来引入。其用途之一是负责在vector的未使用空间上创建对象(这点在STL中详细论述)。placement new的用法如下:

                          A *q = new ( ptr ) A; //ptr指向对象被构造之处

编译器同样给出了与带指针的placement new对应的placement delete,形式如下:

                          void operator delete( void* pMemory, void *ptr ) throw() ;

      

需要注意的有两点:

1、如果程序员自定义了placement new,那么也应定义相应形式的placement delete,否则在调用该placement new构造对象并出现异常时,编译器找不到可用的placement delete来回收空间,这将导致内存泄露!

2、placement delete只有在“伴随placement new调用而触发的构造函数”出现异常时才会被调用。针对一个指针施行的delete绝不会导致调用placement delete。即使这个指针是由placement new返回的,也不会。例如对于上文的指针q,执行语句delete q时,调用的时全局的普通的operator delete,而不是带第二个参数的operator delete。

 


********************************append 2014-9-13***********************************

上面说到placement new的用途之一是在vector的未使用空间上创建对象。下面参考《STL源码剖析》给出部分解释:

在创建vector时,先调用空间配置器void *allocate(size_t n)来分配内存空间(《STL源码剖析》中说明了SGI STL的空间配置器分为两级,并给出了内部实现),再调用void construct(T1 *p, const T2& value)在分配的空间上构造对象。(construct函数包含在头文件<stl_construct.h>中,T1、T2是模板参数,详见《STL源码剖析》51页)

既然是在分配的空间上构造对象,显然要用到placement new,事实正是如此,construct函数内部就调用了placement new,源码如下:

template <class T1, class T2>
inline void construct(T1* p, const T2& value){
    new (p) T1(value);
}

vector的push_back函数内部则是调用construct来在末端加入新元素的。详见《STL源码剖析》122面。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值