Loading

MoreEffect[8] 理解不同含义的new和delete

C++使用new操作符(new operator / new)来完成动态内存的分配,其的实现分为两步:通过operator new分配足够的堆内存,调用构造函数初始化内存对象。类似的,delete首先调用析构函数,然后通过operator delete释放内存。

new、delete操作符和sizeoftypeid一样是语言内置的关键字,不能重载以改变它的含义,但可以重载new操作operator new)、delete操作来改变内存的分配方式。必须要明确,这些操作符所完成的功能被明确固定,定制函数绝不能改变它们完成的功能,只能改变实现功能的方法。

operator new

new调用operator new完成必要的内存分配,其的函数形式为:void * operator new(size_t size);operator new返回一块未经处理的堆内存的首地址,参数size决定的内存块的大小。可见,其和malloc非常接近。

编译器提供了6种operator new的全局重载形式,并允许用户提供自定义的operator new,参数可以和已有形式完全相同(但不能在已有参数形式上增加含默认值的参数,避免引起歧义)。

void *operator new(std::size_t count) throw(std::bad_alloc);//标准版本
void *operator new(std::size_t count, const std::nothrow_t&) throw(); //兼容早版本的new,不会抛出异常
void *operator new(std::size_t count, void *ptr) throw();//placement new
void *operator new[](std::size_t count) throw(std::bad_alloc);//new[]版本
void *operator new[](std::size_t count, const std::nothrow_t&) throw();
void *operator new[](std::size_t count, void *ptr) throw();

在调用new时提供对应的参数以调用合适的operator new

void * memory = operator new(sizeof(Awesome));
Awesome * pObj = new (memory) Awesome;//调用placement new 

重载operator new

重载operator new函数的返回值必须是void *,可以添加新的形参,但第一个参数必须是size_t类型。全局重载函数的参数不需要自定义类型,参数可以和已有的完全一致。

void * operator new(size_t size);//new [type]
void * operator new(size_t size, int arg);//new(int) [type]
void * operator new(size_t size, int arg = 0);//error: 歧义
class Awesome
{
public:
    void * operator new(size_t size)//new Awesome
    {
        cout << "Awesome::operator new" << endl;
        return malloc(size);
    }
};

通过重载可以自定义内存分配的过程,并通过提供合适的参数让new自动调用。当我们设计的类需要更细致的内存管理时,就应该考虑重载类的operator newoperator delete

placement new

placement new是一个特殊的operator new,用于可以在一个未经处理的内存上构造对象。

void *operator new(std::size_t count, void *ptr) throw();//placement new
void * memory = operator new(sizeof(Awesome));
Awesome * pObj = new (memory) Awesome; 

参数ptr执行未经处理的内存,作为new的额外参数。

operator delete

operator deletenew的关系类似于operator newnew的关系。delete会调用析构函数析构对象,然后释放对象占有的内存。换言之,析构函数本身不会释放内存,必须借由operator delete完成。

delete pObj;
//相当于
pObj->~Awesome();
operator delete(pObj);

直接调用operator delete可以释放对象的内存,但对象关联的其它内存就不会被释放,必须在调用operator delete前调用析构函数。

void operator delete(void *);
void operator delete[](void *);

暴露的operator delete只有两个版本。可以重载operator delete

placement delete

placement delete并不能直接调用,编译器只会在placement new构造失败时调用placement delete清理内存。

手动释放placement new生成的对象时应显式调用对象的析构函数,并在需要时在析构之后把内存释放掉。

参考:

https://developer.aliyun.com/article/640510

https://www.zhihu.com/question/22947192

posted @ 2021-08-13 10:02  sandersunkown  阅读(70)  评论(0)    收藏  举报