Effective C++ 条款52

写了placement new也要写placement delete

本文主要内容是对placement new 和 placement delete的介绍,以及在什么情况下使用placement new和placement delete。

对于语句Widget* pw=new Widget;来说,该语句做了两件事情,第一件事情是申请了内存区域;第二件事情是在该内存区上进行对象的构造,即调用构造函数。我们设想其中一种执行情况,当第一件事情完成,而第二件事情出现异常,那么我们应该怎么去处理,很显然我们需要将这部分内存还原回去,于是如何还原回去成了我们需要解决的问题。
这个时候,客户没有能力去归还内存,因为如果Widget构造函数抛出异常,那么pw尚未被赋值,客户手中的指针还没有指向开辟的内存。释放内存的任务落到了C++运行期系统身上。

 class Widget{
    public:
        static void* operator new(std::size_t size, std::ostream& logStream)//非正常形式的new
            throw(std::bad_alloc);
        static void operator delete(void* pMemory, std::size_t size)//正常的class专属delete
            throw();
        ……
    };
Widget* pw = new(std::cerr) Widget;

我们看到上面的代码,当调用new(std::cerr) Widget语句时,我们就进入了Widget的自定义new函数中,当构造函数中出现异常的时候,我们可以在构造函数中调用对应的delete函数,实现内存回收。大家如果得到签名式,回收内存就简单了。

我们先来介绍一下placement new 和 placement delete的介绍,术语placement new意味着带有额外参数的new,如void* operator new(std::size_t, void* pMemory) throw();,placement delete味着带有额外参数的delete。

解决问题的关键变成了如何得到合适的 delete。
根据作者的说明,我们知道
placement delete只有在“伴随placement new调用而触发的构造函数”出现异常时才会被调用。对一个指针施行delete绝不会导致调用placement delete。
这意味对所有placement new我们必须同时提供一个正常的delete和一个placement版本。

class Derived: public Base{
    public:
        ……
        static void* operator new(std::size_t size) throw(std::bad_alloc);//重新声明正常形式的new
    };
    Derived* pd=new (std::clog) Derived;//错误,因为Base的placement new被掩盖了
    Derived* pd1=new Derived;//正确
在缺省情况下,C++在global作用域内提供以下形式的operator newvoid* operator(std::size_t) throw(std::bad_alloc);//normal new
    void* operator(std::size_t, void*) throw();//placement new
    void* operator(std::size_t, const std::nothrow_t&) throw();//nothrow new


class StadardNewDeleteForms{
    public:
        //normal
        static void* operator new(std::size_t size) throw(std::bad_alloc)
        {return ::operator new(size);}
        static void operator delete(void* pMemory) throw()
        {::operator delete(pMemory);}
        //placement
        static void* operator new(std::size_t size, void* ptr) throw(std::bad_alloc)
        {return ::operator new(size, ptr);}
        static void operator delete(void* pMemory, void* ptr) throw()
        {::operator delete(pMemory, ptr);}
        //nothrow
        static void* operator new(std::size_t size, const std::nothrow_t& nt) throw(std::bad_alloc)
        {return ::operator new(size,nt);}
        static void operator delete(void* pMemory,const std::nothrow_t&) throw()
        {::operator delete(pMemory);}
    };

class Widget: public StandardNewDeleteForms{
    public:
        //让这些形式可见
        using StandardNewDeleteForms::operator new;
        using StandardNewDeleteForms::operator delete;
        //添加自己定义的
        static void* operator new(std::size_t size, std::ostream& logStream) throw(std:;bad_alloc);
        static void operator detele(std::size_t size, std::ostream& logStream) throw();
    };
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值