《Effective C++》读书笔记 条款52:写了placement new也要写placement delete

当写一个new表达式

Widget* pw = new Widget;

一共有两个函数会被调用:一个是用以分配内存的operator new,一个是Widget的default构造函数。如果第一个函数调用成功,第二个函数却抛出异常,为了防止内存泄漏,步骤一就需要调用相应的delete以恢复旧观。运行期系统会调用相应的operator delete,在知道哪一个delete该被调用的时候。对于正常的operator new,运行期系统会调用正常的operator delete。但是如果你声明了非正常的operator new,也就是有附带参数的new,(除了size还有其他参数)即placement new,该选择哪一个delete的问题便出现了。

假设,写了一个class专属的operator new,要求接受一个ostream,用来志记相关分配信息,同时又写了一个正常形式的class专属operator delete:


class Widget
{
public:
	static void* operator new(std::size_t, std::ostream logStream) throw(std::bad_alloc);
	static void operator delete(void* pMemory, std::size_t size) throw();
};

现在考虑动态创建一个Widget

Widget* pw = new (std::cerr) Widget;//调用operator new并传递cerr为其ostream实参;
                                    //这个动作会在构造函数抛出异常时泄漏内存                              

现在,如果构造函数抛出异常,运行期系统会寻找参数个数和类型都和operator new相同的某个operator delete,operator delete应该也是placement delete:

void operator delete(void*,std::ostream&) throw();

而Widget中没有该函数,所以会造成内存泄漏。所以正确的应该是

class Widget
{
public:
	static void* operator new(std::size_t, std::ostream logStream) throw(std::bad_alloc);
	static void operator delete(void* pMemory) throw();
    static void operator delete(void* pMemory,std::ostream& logStream) throw();
};

如果分配成功,调用delete pw;调用的是正常形式的operator delete,绝对不会调用placemenet delete。

 

由于成员函数的名称会掩盖外围作用域中的相同名称,所以必须小心避免让class专属的news掩盖其他news。同样的derived class会掩盖global版本和继承而来的operator new版本。对于delete也是如此,不能掩盖与new相关的delete。

解决方式,就是在类中包含所有正常形式的new和delete,对于继承,可以利用继承机制和using声明式取得标准形式。

 

请记住

1.当你写一个placement operator new,请确定也写出了对应的placement operator delete。如果没有这样做,你的程序可能会发生隐微而时断时续的内存泄漏。

2.当你声明placement new和placement delete,请确定不要无意识地掩盖了它们的正常版本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值