new 和 delete 都做了什么 (C++)

new & delete 过程

当我们使用关键字 new 在堆上动态创建一个对象A时,比如 A* p = new A() ,它实际上做了三件事:

1.向堆上申请一块内存空间(做够容纳对象A大小的数据)( operator new )

2.使用 static_cast 进行类型转换

3.调用构造函数 (调用A的构造函数(如果A有的话))( placement new)

4.返回正确的指针。

当我们使用 delete 的时候,也是一样的,其行为如下:

  1. 定位到指针p所指向的内存空间,然后根据其类型,调用其自带的析构函数(内置类型不用)

  2. 然后释放其内存空间(调用 operator delete ,将这块内存空间标志为可用,然后还给操作系统)

  3. 将指针标记为无效(指向NULL)。

operator new 和 operator delete

这两个其实是 C++ 语言标准库的库函数,原型分别如下:

void *operator new(size_t);     //allocate an object
void *operator delete(void *);    //free an object

void *operator new[](size_t);     //allocate an array
void *operator delete[](void *);    //free an array

operator new 和operator new功能都是仅仅分配内存,底层调用了 malloc 函数。 operator new是给new用的,operator new[]是给new[]用的。而且可以被重载。比如可以重载该函数,实现全局调用的打 log。

    void * operator new(size_t size)
    {
        cout << "call operator new " << endl;
        return ::operator new(size);
    }

数组怎么办?

调用 operator new [] 函数后,C++ 的做法是在分配数组空间时,在头部多分配了 4 个字节的大小,专门保存数组的大小。当然,编程时拿到的是对象数组的指针,而不是所有分配空间的起始地址。

调用 operator delete [] 函数后:根据从数组对象指针前面的 4 个字节中取出的值,进行依次析构,这里要注意:

  • 传入 operator delete [] 函数的参数不是数组对象的指针 p,而是 p 的值减 4。(因为做减法之后,才是真正的分配空间时的起始地址)

为什么 new/delete 、new []/delete[] 要配对使用?

我们看看如果是带有自定义析构函数的类类型,用 new [] 来创建类对象数组,而用 delete 来释放会发生什么?用上面的例子来说明:

class A *pAa = new class A[3];
delete pAa;

那么 delete pAa; 做了两件事:

  • 调用一次 pAa 指向的对象的析构函数;
  • 调用 operator delete(pAa); 释放内存。

显然,这里只对数组的第一个类对象调用了析构函数,后面的两个对象均没调用析构函数,如果类对象中申请了大量的内存需要在析构函数中释放,而你却在销毁数组对象时少调用了析构函数,这会造成内存泄漏。

上面的问题你如果说没关系的话,那么第二点就是致命的了!直接释放 pAa 指向的内存空间,这个总是会造成严重的段错误,程序必然会崩溃!因为分配的空间的起始地址是 pAa 指向的地方减去 4 个字节的地方。这里应该传入参数设为那个地址!

placement new

有时候你真的会想直接调用一个构造函数,去针对一个已经被定义的对象调用其构造函数生成对象,但这没有什么意义,因为构造函数用来对对象进行初始化,而一个对象只能只能初始化一次。但是你偶尔会有一些分配好的原始内存,你想要在上面构建已知的对象,这样的话,你就需要用到 placement new。placement new 是用来实现定位构造的,因此可以实现 new operator 三步操作中的第二步,也就是在取得了一块可以容纳指定类型对象的原始内存后,在这块内存上构造出一个对象有点类似于

char s[sizeof(string)];
string* p = (string*)s;
new(p) string("memory"); //p->string::string("memory");

 

posted @ 2021-12-19 17:07  Clovran-Wong  阅读(350)  评论(0编辑  收藏  举报