C语言用malloc、calloc、realloc、free来进行动态内存管理,而C++用new和delete来进行动态内存管理。当然因为C++兼容C,所以在C++中同样可以使用malloc等函数。
那为什么C++会有new和delete?
class ListNode
{
public:
ListNode(int x)
:_val(x)
, _next(nullptr)
{
cout << "ListNode()" << endl;
}
~ListNode()
{
cout << "~ListNode()" << endl;
if(_next)
{
free(_next);
}
}
public:
int _val;
ListNode* _next;
};
//这是用malloc申请节点
ListNode* BuyListNode(int x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->_next = NULL;
newnode->_val = x;
return newnode;
}
//这是用new申请结点
ListNode* BuyListNode(int x)
{
ListNode* newnode = new ListNode (x);
delete newnode;
return newnode;
}
当数据类型是内置类型时,malloc申请节点不会初始化,calloc会全部初始化为0;当数据类型是自定义类型时,malloc和calloc用起来就有点麻烦了。因此C++提出自己的动态内存管理方式:new和delete。new可以开辟空间的同时调用构造函数初始化,delete释放空间的同时会调用析构函数。
int main()
{
int* n1 = new int;//new + 类型,申请一个int类型的空间
int* n2 = new int(1);//new + 类型 + (n),申请空间后,对其初始化
char* n3 = new char[10]{ 'a','b','c' };//申请10个字符的空间,并初始化前三个,其余置为0
int* n4 = new int[10]{ 1,2,3 };
delete n1;
delete n2;
delete[]n3;
delete[]n4;
//注意:
// 1.new和delete是操作符,malloc和free是函数
// 2.申请和释放单个元素的空间用new和delete,申请和释放连续空间时用new[]和delete[]。
// 3.单个元素初始化用()圆括号,连续的元素初始化用{ }大括号
return 0;
}
new和delete申请自定义类型时,会调用其构造函数和析构函数。这也是new和delete与malloc和free最大的区别。
//例子
class ListNode
{
public:
ListNode(int x)
:_val(x)
, _next(nullptr)
{
cout << "ListNode()" << endl;
}
~ListNode()
{
cout << "~ListNode()" << endl;
free(_next);
}
public:
int _val;
ListNode* _next;
};
int main()
{
ListNode* n1 = new ListNode(1);
delete n1;
return 0;
}
//例子2
ListNode* n2 = new ListNode[10]{ 1,2,3,4,5,6, 7,8,9,10};
//也可以这样初始化new ListNode[10]{ListNode(1),ListNode(2),ListNode(3),……};
delete []n2;
//调用10次构造函数和析构函数。ListNode没有提供默认构造函数,所以必须全部初始化。
//如果有提供默认构造函数,就可以不完全初始化,其余的ListNode会调用默认构造
注意
new和delete,malloc和free一定要匹配使用,不能用free去释放new的变量,不能用delete去释放malloc的变量。
所以new = operator new + 自定义类型调用构造函数,delete = 先调用析构函数释放资源 + 再operator delete。
定位new表达式是在已经分配的内存空间调用构造函数初始化一个对象。
new(指针)类型或者new(指针)类型(初始值)
当我们申请空间后,忘记或者因为程序错误而忘记释放空间,可能导致内存泄漏。内存泄漏的危害很大,尤其是对一些长期运行的程序,会导致其响应越来越缓慢。
那么该怎么避免内存泄露呢?第一,养成良好的代码习惯,申请的空间匹配去释放;第二,利用智能指针来管理资源。
共同点:它们都是从堆上申请空间,且都需要手动释放。
不同点:
(1)malloc和free是函数,new和delete是操作符。
(2)malloc不会初始化,new会初始化。
(3)如果申请的空间来存储自定义类型,new会调用其构造函数,delete会调用其析构函数,而malloc和free不会。
(4)malloc申请空间失败会返回null,而new申请空间失败会抛异常。
(5)malloc返回值为void*,需要强制类型转换,而new不需要。
(6)在申请空间时,malloc需要手动计算申请空间大小,而new不需要,只需要接类型和个数即可。