Effective C++(写了placement new就要写placement delete)


author:

  • luixiao1223
    title: 写了placement new就要写placement delete

问题

Widget *w=new Widget;
  1. 假如分配内存成功了.
  2. 但是Widget的构造函数失败了

出现这种情况怎么办?因为用户是拿不到w指针的.所以这个任务只能有运行系统自己负责.

placement new

void* operator new(std::size_t, void* pMemory) throw(); // 你自定义placement new时.可以自定义第二个参数

这个版本的new已经纳入C++标准库了.你只需要 #include <new> 即可.
构造函数失败且你是一个自定义的placement new怎么办?

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

我们来看看如果客户这样进行调用

Widget *pw = new (std::cerr) Widget;

如果内存分配OK,但是构造函数失败怎么办?运行系统这下是没办法释放内存的.因为它无法找到一个含有placement的delete函数.

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

为什么有两个delete?因为一个delete为一般正常形式的delete.它的作用是正常删除的时候用.加入内存分配OK.构造函数也OK.你成功拿到了pw.这个时候你手工删除pw就是调用的正常形式的delete.换句话说,placement
delete是在内存分配OK,但是构造函数不OK的时候才调用.

注意覆盖问题

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

Base *pb = new Base; // Error
Base *pb = new (std::cerr) Base; // OK

class Derived: public Base {
public:
    static void* operator new(std::size_t size) throw(std::bad_alloc);
};

Derived *pd = new (std::clog) Derived; // Error
Derived *pd = new Derived; // OK

建议的一种封装继承模式

class StandardNewDeleteForms {
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( )
    {
        return ::operator new(size, ptr);
    }

    static void operator delete(void *pMemory, void *ptr) throw() {
        return ::operator delete(pMemory, ptr);
    }

    // No throw
    static void* operator new(std::size_t size, const std::nothrow_t& nt) throw()
    {
        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 delete(void *pMemory, std::ostream&logStream) throw();
};
发布了127 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/luixiao1220/article/details/104492448