c++ new delete
=====================
delete是我们c++中的关键字,我们都知道它和new是配套使用的,有new就有delete不然会存在内存泄漏的问题。但是我们使用过delete的同学可能会发现delete有两种形式,一种是delete [],那这两个有什么区别呢?
1、delete 释放new分配的单个对象指针指向的内存
2、delete[] 释放new分配的对象数组指针指向的内存
3、delete处理单个类类型,先会调用析构函数,释放它所占资源,然后释放它所占内存空间。
4、delete处理数组类类型的时候,会对每一个数组对象都调用它们的析构函数,然后再释放它们所占用的内存空间。所以对于类类型的数组如果不调用delete[],那就只调用了下标为0的对象的析构函数,可能会产生问题。
5、两个都会释放所占内存,对于内置类型不管是数组还是单个对象,都可以混用,没有关系,因为对于内置类型,它只干一件事,就是释放它们所占内存
6、如果对于单个类对象,delete和delete[]都可以,因为delete是知道它要释放多大空间的,加不加[]括号的区别是对不对每个对象调用析构函数,如果只有一个的话,它就调用一次,所以没有关系。
示例1:
int *p =new int;
delete p; //ok p指向了有一个int的内置类型大小的空间,delete直接释放了它。
//delete []p; ok
示例2:
int *p = new int [10](); //ok
delete p; //ok 内置类型不需要调用析构函数
delete [] p; //ok 效果和上面一样
示例3:
int *p =new A () ;
delete p; //ok
delete []p;//ok
示例4:
int *p =new A[10]();
delete p; //不行,只调用p[0]的析构函数
delete [] p; //可以,会调用构造函数
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/Betty2017/article/details/78634257
================
new对象时,类名后加括号与不加括号的区别
【1】默认构造函数
关于默认构造函数,请参见随笔《类中函数》
请看测试代码:
1 #include <iostream>
2 using namespace std;
3
4 // 空类
5 class Empty
6 {
7 };
8
9 // 一个既有默认构造函数又有自定义构造函数的类
10 class Base
11 {
12 public:
13 Base() // 默认构造函数
14 {
15 cout << " default Base construct " << endl;
16 m_nValue = 100;
17 }
18
19 Base(int nValue) // 自定义构造函数
20 {
21 cout << " custom Base construct " << endl;
22 m_nValue = nValue;
23 }
24
25 private:
26 int m_nValue;
27 };
28
29 // 一个具有复合默认构造函数的类
30 class custom
31 {
32 public:
33 custom(int value = 100)
34 {
35 cout << " default && custom construct " << endl;
36 m_nValue = value;
37 }
38
39 private:
40 int m_nValue;
41 };
42
43 int main()
44 {
45 Empty* pE1 = new Empty;
46 Empty* pE2 = new Empty();
47
48 Base* pB1 = new Base;
49 Base* pB2 = new Base();
50 Base* pB3 = new Base(200);
51
52 custom* pC1 = new custom;
53 custom* pC2 = new custom();
54
55 delete pE1;
56 delete pE2;
57
58 delete pB1;
59 delete pB2;
60 delete pB3;
61
62 delete pC1;
63 delete pC2;
64
65 return 0;
66 }
67
68 // run out:
69 /*
70 default Base construct
71 default Base construct
72 custom Base construct
73 default && custom construct
74 default && custom construct
75 */
至此足以。
【2】加括号与不加的区别
(1)加括号
1. 若括号为空,即无实参项,那么理解为调用默认构造函数;
2. 若括号非空,即有实参项,可以理解为调用重载构造函数,或复合默认构造函数。
(2)不加括号
调用默认构造函数,或复合默认构造函数。
【3】默认构造函数 与 复合默认构造函数的区别
默认构造函数:编译器会为每一个类默认提供一个构造函数,称之为默认构造函数。默认构造函数一般参数为空。
复合默认构造函数:一个由用户自定义的所有形式参数都赋有默认值的构造函数,称之为复合默认构造函数。
两者联系:
一个类中,若一旦有一个用户自定义构造函数,那么由编译器提供的默认构造函数就不再存在。用户自定义的构造函数为默认构造函数的重载版。
默认构造函数不复存在时,用户必须为这个类再自定义一个复合默认构造函数(选所有自定义构造函数其中之一,把形式参数均赋默认值即可)。
不论自定义构造函数(即构造函数的重载版)有多少个,只允许有一个复合默认构造函数
============
一直对C++中的delete和delete[]的区别不甚了解,今天遇到了,上网查了一下,得出了结论。做个备份,以免丢失。
C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]。
关于 new[] 和 delete[],其中又分为两种情况:(1) 为基本数据类型分配和回收空间;(2) 为自定义类型分配和回收空间。
请看下面的程序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include <iostream>; using namespace std; class T { public : T() { cout << "constructor" << endl; } ~T() { cout << "destructor" << endl; } }; int main() { const int NUM = 3; T* p1 = new T[NUM]; cout << hex << p1 << endl; // delete[] p1; delete p1; T* p2 = new T[NUM]; cout << p2 << endl; delete [] p2; } |
大家可以自己运行这个程序,看一看 delete p1 和 delete[] p1 的不同结果,我就不在这里贴运行结果了。
从运行结果中我们可以看出,delete p1 在回收空间的过程中,只有 p1[0] 这个对象调用了析构函数,其它对象如 p1[1]、p1[2] 等都没有调用自身的析构函数,这就是问题的症结所在。如果用 delete[],则在回收空间之前所有对象都会首先调用自己的析构函数。
基本类型的对象没有析构函数,所以回收基本类型组成的数组空间用 delete 和 delete[] 都是应该可以的;但是对于类对象数组,只能用 delete[]。对于 new 的单个对象,只能用 delete 不能用 delete[] 回收空间。
所以一个简单的使用原则就是:new 和 delete、new[] 和 delete[] 对应使用。
====================
摘要
在C++中通过new动态分配的内存,必须要要用delete进行释放,而使用使用new[]申请的内存释放时,标准做发用delete[],但有时用delete也能正常释放。那到底delete带方括号[]和不带方括号[]有什么区别呢?以下通过实例代码,测试一下C++中通过new[] 创建的内存在释放时是否一定需要在delete后加[]
基本数据类型
对于基本数据类型(如char, int, unsigned int, short int等),如果动态申请一个数组类型,如下:
int *a = new int[10 * 1024 * 1024];
...
delete a; // 方式1,不带方括号
int *b = new int[10 * 1024 * 1024];
...
delete [ ] b; //方式2,带方括号
- 1
- 2
- 3
- 4
- 5
- 6
- 7
以上示例代码,使用了两种方法分配了一个10M int类型的数组,实际占用空间是40M字节。
肯定会不少人认为方式1存在内存泄露,然而事实上是不会!
通过观察任务管理器中,进程占用的内存可以看到,以上两种方式在申请内存后,进程占用的内存会增加40MB,而释放后就会还原到分配前的内存占用。
针对基本数据类型,方式1和方式2均可正常工作,因为:基本的数据类型对象没有析构函数,并且new 在分配内存时会记录分配的空间大小,则delete时能正确释放内存,无需调用析构函数释放其余指针。因此两种方式均可。
自定义数据类型
对于自定义的class(类),通过new申请了一个对象数组,返回一个指针,对于此对象数组的内存释放,需要做两件事情:一是释放最初申请的那部分空间,二是调用析构函数完成清理工作。
案例1
我们来看一个示例:
#include <iostream>
using namespace std;
class TestClass
{
public:
int a;
};
int main()
{
TestClass* p1 = new TestClass[10 * 1024 * 1024];
delete p1; //方式1,不带[]
TestClass* p2= new TestClass[10 * 1024 * 1024];
delete[] p2; //方式2,带[]
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
以上代码两种释放方式,都能正常释放,通过观察进程的内存占用,也能看出两种方法分配内存后进程占用的内存相应增加,两种方法delete后,内存都能相应的减少。
案例2
我们将案例1稍微修改一下,代码如下:
#include <iostream>
using namespace std;
class TestClass
{
public:
int* p;
TestClass()
{
p = new int[1];
}
~TestClass()
{
delete[] p;
}
};
int main()
{
TestClass* p1 = new TestClass[10 * 1024 * 1024];
delete p1; //方式1,不带[]
TestClass* p2= new TestClass[10 * 1024 * 1024];
delete[] p2; //方式2,不带[]
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
以上代码,将TestClass中修改为在类中有动态分配内存,并在析构时释放。方式1,直接会报如下异常信息:
继续执行会报如下错误:
而方式2就能正常释放,并且从任务管理器观察的内存变化情况来看,占用的内存也都相应的被释放掉了。
对于内存空间的清理,由于申请时记录了其大小,因此无论使用delete还是delete[]都能将这片空间完整释放,而问题就出在析构函数的调用上,当使用delete时,仅仅调用了对象数组中第一个对象的析构函数,而使用delete []的话,将会逐个调用析构函数。
异常原因
我们再来看如下代码
#include <iostream>
using namespace std;
class TestClass
{
public:
TestClass() { cout << "constructor" << endl; }
~TestClass() { cout << "destructor" << endl; }
};
int main()
{
const int NUM = 3;
TestClass* p1 = new TestClass[NUM];
cout << hex << p1 << endl; //输出P1的地址
// delete[] p1;
delete p1; //方式1,不带[]
cout << endl;
TestClass* p2 = new TestClass[NUM];
cout << p2 << endl; //输出P2的地址
delete[] p2;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
输出结果为:
constructor
constructor
constructor
001174D4
destructor
- 1
- 2
- 3
- 4
- 5
此时就直接报前文所说的异常了。
而将方式1的代码屏蔽掉,直接执行方式2的代码,输出结果如下:
constructor
constructor
constructor
00A13514
destructor
destructor
destructor
- 1
- 2
- 3
- 4
- 5
- 6
- 7
可以看到,不加[]时只调用了一次析构函数,然后就报异常了,而加了[]调用了上次析构函数。
总结
通过实例代码,测试了C++中通过new[] 创建的内存在释放时是否需要在delete后加[]。从测试结果来看,如果是基本数据类型,delete时加方括号和不加方括号都是一样的效果。如果是自定义的class,分两种情况:class中有动态分配的资源和没有动态分配的资源,有动态分配的资源时,也就是需要通过析构函数来释放动态分配的资源,则必须使用delete[],否则就会报异常(也可能开发环境并不会报异常,但由于没有成功调用析构函数释放资源,会造成内存泄漏);而没有动态分配的资源时,delete和delete[]都能正常释放掉内存。所以,通过new[]创建的内存,在释放时,最好还是使用delete[]的方式释放更加保险。
原文地址:https://www.cfnotes.com/archives/150
==============================================
参考:
https://www.cnblogs.com/Braveliu/p/4263145.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!