C++ Exceptional 重载运算符new和delete时要注意的地方

首先看下面一段代码,找出代码中存在的问题:

class B
{
public:
    virtual ~B();
    void operator delete(void*, size_t) throw();
    void operator delete[](void*, size_t) throw();
    void f(void*, size_t) throw();
};

class D : public B
{
public:
    void operator delete (void*) throw();
    void operator delete[](void*) throw();
};

下面我来说一下以上代码的问题:
1. 有operator delete但没有相对应的operator new,这是很容易引起内存问题的。
2. operator delete 没有声明成静态的。当然这里虽然没有声明成静态的,编译器也会默认把operator deleteoperator new 当作静态的函数,但为了可读性,还是要把operator deleteoperator new 显式的声明为静态的。
3. 注意到基类里声明operator delete 的时候多了一个size_t 参数,而派生类里是没有的,这样会有什么问题吗?答案是没有任何影响,写与不写都可以,看自己的喜好。

另外,看一下下面的代码:

B* pb1 = new D;
delete pb1;

问题是以上代码可以正确调用到D的operator delete吗,答案是可以的。这个时候你可能会问了,既然operator delete 是静态的,那为什么用pb1可以调用到类D的operator delete 呢?这个就要感谢编译器为我们做的事情了。首先类B的析构函数是虚的,所以再调用pb1的析构函数时,会调用到类D的析构函数中去,而这个时候,c++会在析构函数中设置一个标志,如果说这个对象是静态分配的,那这个标志为false,但是,如果这个对象是动态分配的,那么这个标志就会为true。而当这个标志为true的时候,c++就会调用相应的delete去释放掉这块内存区域。这也就解释了为什么可以调到类D中的operator delete 了。当然,这里类B的析构函数如果是非虚的,那么在调用pb1的析构函数时,就不会调用到类D的了,这个时候不但类D没有正确被析构,相应的operator delete 调用也是错误的。

下面再来看一段代码:

class ShareMemery
{
public:
    static void* Allocate(size_t s)
    {
        return OsSpecificShareMemAllocation(s);
    }
    static void Deallocate(void *p)
    {
        OsSpecificShareMemDeallocation(p);
    }
};
class Y
{
public:
    static void* operator new(size_t s,
                       SharedMemery& m) throw(bad_alloc)
    {
        return m.Allocate(s);
    }
}
SharedMemery shared;
...
new (shared) Y; // if Y::Y() throws, memory is leaked

我相信读者应该很快能看出上面代码的问题,问题就是缺少了相对应的operator delete。下面我们完善一下以上的类:

class Y
{
public:
    static void* operator new(size_t s,
                       SharedMemory& m) throw(bad_alloc)
    {
        return m.Allocate(s);
    }
    static void operator delete(void* p, SharedMemory& m) throw()
    {
        return m.Deallocate(p);
    }

    static void operator delete(void* p) throw()
    {
        return SharedMemory::Deallocate(p);
    }

}

首先这里要注意的是提供了两个operator delete ,为什么要这样呢?
第一,一定要有一个和operator new 相对应的operator delete,这里的对应只的是,除了第一个参数外,剩余的参数可以一一对应,之所以要这样配对出现,是为了避免出现内存泄露。假设在调用我们自己的operator new 时,对象的初始化出现了异常,这个时候c++会去调用配对的operator delete 去释放内存,加入编译器找不到配对的operator delete,那么这个内存就泄露了。另外,为什么提供第二种形式的operator delete呢,这是因为我们在调用delete Y 的时候,此时并不会调用配对的那个,因为这里没有传参,也是不可以传参的,所以要提供第二种形式的operator delete
综上所述,其实最重要的就一点,那就是自定义的operator newoperator delete 一定要配对出现,要不然的话,就会出现内存泄露,甚至程序崩溃等问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值