c++ new operator和operator new,delete operator和operator delete

1 new operator 和 operator new,delete operator 和 operator delete

new operator: c++中的关键字new,如A *a = new A;

operator new:c++中的一个操作符,并且可以被重载(类似加减乘除操作符)

operator new can be called explicitly as a regular function, but in C++, new is an operator with a very specific behavior: An expression with the new operator, first calls function operator new (i.e., this function) with the size of its type specifier as first argument, and if this is successful, it then automatically initializes or constructs the object (if needed). Finally, the expression evaluates as a pointer to the appropriate type.

operator new和operator delete的声明

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

例如:

A* a = new A;

分三步:

1 分配内存;2 调用A()构造对象;3 返回分配指针

事实上,分配内存这一操作就是由operator new(size_t)来完成的,如果类A重载了operator new,那么将调用A::operator new(size_t ),否则调用全局::operator new(size_t ),后者由C++默认提供。因此前面的步骤也就是:

1 调用operator new (sizeof(A)); 2 调用A::A(); 3 返回指针

下面的图是一个具体的示例

简单总结下:

  • 首先需要调用上面提到的 operator new 标准库函数,传入的参数为 class A 的大小,这里为 8 个字节,至于为什么是 8 个字节,你可以看看《深入 C++ 对象模型》一书,这里不做多解释。这样函数返回的是分配内存的起始地址,这里假设是 0x007da290。
  • 上面分配的内存是未初始化的,也是未类型化的,第二步就在这一块原始的内存上对类对象进行初始化,调用的是相应的构造函数,这里是调用 A:A(10); 这个函数,从图中也可以看到对这块申请的内存进行了初始化,var=10, file 指向打开的文件。
  • 最后一步就是返回新分配并构造好的对象的指针,这里 pA 就指向 0x007da290 这块内存,pA 的类型为类 A 对象的指针。

delete pA 的过程:

delete 就做了两件事情:

  • 调用 pA 指向对象的析构函数,对打开的文件进行关闭。
  • 通过上面提到的标准库函数 operator delete 来释放该对象的内存,传入函数的参数为 pA 的值,也就是 0x007d290。

 

2 operator new的三种形式

throwing (1)    
void* operator new (std::size_t size) throw (std::bad_alloc);
nothrow (2) 
void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) throw();
placement (3)   
void* operator new (std::size_t size, void* ptr) throw();

(1)(2)的区别仅是是否抛出异常,当分配失败时,前者会抛出bad_alloc异常,后者返回null,不会抛出异常。它们都分配一个固定大小的连续内存。

A* a = new A; //调用throwing(1)
A* a = new(std::nothrow) A; //调用nothrow(2)

3 new[] 和 delete[]

假设 class A *pAa = new A[3];

从这个图中我们可以看到申请时在数组对象的上面还多分配了 4 个字节用来保存数组的大小,但是最终返回的是对象数组的指针,而不是所有分配空间的起始地址。

这样的话,释放就很简单了:

delete []pAa;

这里要注意的两点是:

  • 调用析构函数的次数是从数组对象指针前面的 4 个字节中取出;
  • 传入 operator delete[] 函数的参数不是数组对象的指针 pAa,而是 pAa 的值减 4。

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

4.1 使用new[]分配内存,delete释放

内置类型:


int *pia = new int[10];
delete []pia;

内置类型因为不需要调用析构函数,所以使用new[]分配的内存的时候没有多分配4个字节保存数组大小;所以此时使用delete 释放内存不会有问题

带有自定义析构函数的类类型:

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

问题有两点,第一点是只对第一个对象调用了析构函数,剩下两个对象没有调用析构函数,如果类对象中申请了大量的内存需要在析构函数中释放,而你却在销毁数组对象时少调用了析构函数,这会造成内存泄漏;

第二点是致命的,直接释放 pAa 指向的内存空间,这个总是会造成严重的段错误,程序必然会崩溃!因为分配的空间的起始地址是 pAa 指向的地方减去 4 个字节的地方。你应该将传入参数设为那个地址!

4.2 使用new分配内存,delete[]释放

同4.1进行分析

总的来说,记住一点即可:new/delete、new[]/delete[] 要配套使用总是没错的!

5 动态创建对象时的初始化问题

int *a = new int(5)  //allocates an integer, set to 5. (same syntax as constructors)

int *a = new int     //allocates an integer,明确不初始化,内置类型的对象无初始化

int *a = new int()  //allocates an integer,采用值初始化,将*a初始化为0

 string *ps = new string(10,'9')    //使用给定的值初始化该内存空间(十个9的字符串)

string *ps = new string                //明确不初始化,但是string会使用默认构造函数初始化(initialized to empty string)

string *ps = new string()             //对于提供了默认构造函数的类类型,无论程序是明确的不初始化还是要求进行值初始化,都会自动调用默认构造函数初始化该对象

int *a = new int[5];

int *a = new int[5]();

原理同上(没有 int *a = new int[5](9) 这种写法)

 

 

参考文章:

https://blog.csdn.net/WUDAIJUN/article/details/9273339

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值