智能指针的引入正是为了防止无意之间写出有内存泄漏的程序。内存释放的工作将交给智能指针来完成,在很大程度上能够避免程序代码中的内存泄漏。
1.new/delete探秘
new/delete是什么
new/delete和malloc/free最明显的区别之一就是使用new生成一个类对象时系统会调用该类的构造函数,使用delete删除一个类对象时系统会调用该类的析构函数(释放函数)。既然有调用构造函数和析构函数的能力,这就意味着new和delete具备针对堆所分配的内存进行初始化(把初始化代码放在类的构造函数中)和释放(把释放相关的代码放在类的析构函数中)的能力,而这些能力是malloc和free所不具备的。operator new()和operator delete()
new运算符做了两件事:①分配内存;②调用构造函数初始化该内存。
delete运算符也做了两件事:①调用析构函数;②释放内存。new如何记录分配的内存大小供delete使用
不同编译器的new内部都有不同的实现方式申请和释放一个数组
为数组动态分配内存时,往往需要用到[],如new[…],而释放数组时,往往也要用到[],如delete[…],这意味着,往往new[]和delete[]要配套使用。为什么new/delete、new[]/delete[]要配对使用
如果一个对象,是用new[]分配内存,而却用delete(而不是delete[])来释放内存,那么这个对象满足的条件是:对象的类型是内置类型(如int类型)或者是无自定义析构函数的类类型。
A * pA = new A[2];
delete pA;
那事情反过来看,如果类A书写了自己的析构函数,则用new[]为对象数组分配内存,而用单独的delete来释放内存,就会报异常。
A * pA = new A[2];
delete pA;
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
A()
{
cout << "A" << endl;
}
int m_i;
};
int main()
{
{
int* pointi = new int;
string* mystr = new string;
}
{
int* pointi = new int(100);
string* mystr2 = new string(5, 'a');
vector<int>* pointv = new vector<int>{ 1,2,3,4,5 };
}
{
string* mystr2 = new string();
int* pointi3 = new int();
}
{
A* pa1 = new A;
A* pa2 = new A();
}
{
string* mystr2 = new string(5, 'a');
const char* p = mystr2->c_str();
auto mystr3 = new auto(mystr2);
delete mystr2;
delete mystr3;
}
{
const int* pointci = new const int(200);
cout << "断点放到这里方便观察" << endl;
delete pointci;
}
{
char* p = nullptr;
delete p;
delete p;
}
{
int i;
int* p = &i;
}
{
int* p = new int();
int* p2 = p;
delete p2;
}
{
const int* pci = new const int(300);
delete pci;
}
{
int* pci = new int(300);
delete pci;
*pci = 900;
}
return 0;
}