new、new[]和new()

本文深入探讨了C++中的内存管理,包括new运算符如何调用构造函数并分配内存,delete如何执行析构函数并释放内存。详细解释了new[]和delete[]必须配对使用的原因,以防内存泄漏,并提到了operatornew和operatordelete在内存分配和释放中的角色。此外,还介绍了定点new的用法以及如何重载这些操作符。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


new是怎么调用的?

这里是一条new的使用语句:

A *pc = new A(1, 2);

这条语句,编译器会转化为下面样子:

A* pc;
try {
	void* mem = operator new(sizeof(A)); //申请内存
	pc = static_cast<A*>(mem);           //类型转换
	pc->A::A();                          //调用构造函数
}
catch (std::bad_alloc) {
	......
}

所以,当我们使用new的时候,它有两个作用:一是申请内存,二是调用相应的构造函数

那么delete呢?

这是一条司空见惯的delete的使用语句:

delete pc;

一样的,编译器也将该语句转化为下面这样:

pc->~A();                  //调用析构函数
operator delete(pc);             //释放内存

那么,delete的作用就是先调用相应的析构函数,再释放内存

new[]和delete[]为什么要成对使用?

调用了new[]为什么一定要调用delete[]?对于不包含指针的成员变量的类来说可能没有影响。但是对于包含有指针的成员变量来说通常都存在影响(见下图)。

string *pStr = new String[3];
delete[] pStr;

new出对象的内存分布
上图是new出对象的内存分布图。
因为delete[]会唤起多次析构函数,当存在带有指针变量时,在delete[]时需要先调用析构函数处理这些指针指向的空间。如果上图仅仅执行delete pStr,表示只调用了一次析构函数,处理了其中的一个指针指向的空间后就进行了释放了pStr所指向的内存,这样就造成了内存泄露

注意到了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 delete和operator delete[]调用了free即可(嗯,很多创建删除新对象什么的函数最后的指向都是malloc和delete)。
同时,以上四个函数都是可以重载的,一般默认调用的是全局的operator new,operator new[],operator delete和operator delete[]。但是,我们对这两个函数进行重载的时候,很少会对全局的operator new,operator new[],operator delete和operator delete[]进行重载,这样做的话,那影响可太大了。因此,我们都是在类中对这两个函数进行重载(记得是static,不过编译器也默认为该类函数是static,毕竟对象都没有,怎么由对象调用该函数创建对象)。

new()怎么用?

首先看看这段代码:

char *buf = new char[sizeof(A)*3];
A *pc = new(buf) A(1,2);

这段代码中的new()也称作定点new,这是因为这个new不需要自己申请空间,直接就在我们传进去的buf里调用构造函数创建对象。被编译器转化为如下:

A* pc;
try {
	void* mem = operator new(sizeof(A), buf); //申请内存
	pc = static_cast<A*>(mem);                //类型转换
	pc->A::A();                               //调用构造函数
}
catch (std::bad_alloc) {
	......
}

而这里的operator new的代码如下:

void* operator new(size_t, void* loc)
{
	return loc;
}

没有自己申请空间,只是将loc的地址返回。
但是new()还有别的形式,这些可不是定点new。比如下列代码:

A *pA = new(100, 'a') A;

也就是重载了类成员operator new(),使其参数列表不同。但是第一个参数必须是size_t,其余参数以new所指定的参数为初值(这是因为没有小括号的时候,类的代大小会被传递给operator new作为第一个参数,此时的类型就是size_t)。

delete()有点复杂

当然,我们也可以重载类成员operator delete(),但是一般来说是绝对不会被delete调用的。只有当new所调用的构造函数抛出异常时,才会调用这些相对应的重载的operator delete()。这样设计的目的是归还未能完全创建成功的object所占用的memory。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值