在C++中经常遇到内存的开辟和释放问题,最近在做项目的时候遇到了一个关于new和delete内存释放的问题,所以总结下这个问题。在C++ primer中,delete一般用来释放单个对象的内存,delete[]用来释放多个对象的内存。但是实际的情况比较复杂,特别是涉及到自己定义的类以及类中还有指针内存开辟的问题的时候。以下分三种情况来讨论。
一、基本数据类型指针的内存的开辟和释放。
针对基本数据类型的指针的内存开辟和释放,delete和delete[]没有任何区别,都可以实现对内存的释放。eg:
int* pdata = new int [10];
delete[] pdata; //情况1
pdata = new int [10];
delete pdata; //情况2
pdata = new int;
delete pdata; //情况3
pdata = new int;
delete[] pdata;//情况4
以上四种情况都可以,都可以通过编译并释放指针pdata所开辟的内存。
二、自定义的类对象指针的内存和开辟和释放(类中没有内存的开辟)。
针对这种情况,delete和delete[]就有了区别。看以下例程:
类的声明如下:
class CImage
{
public:
int width;
int height;
CImage(int w, int h);
CImage();
~CImage();
};
CImage::CImage()
{
cout << "构造函数2被执行" << endl;
}
CImage::CImage(int w, int h)
{
width = w;
height =h;
cout << "构造函数1被执行" << endl;
}
CImage::~CImage()
{
cout << "析构函数被执行" << endl;
}
主函数如下:
{
CImage* pImg = new CImage[10];
delete pImg; //情况1
CImage* pImg = new CImage[10];
delete[] pImg;; //情况2
CImage* pImg = new CImage(3, 4);
delete[] pImg; //情况3
CImage* pImg = new CImage(3, 4);
delete pImg;//情况4
cout << "通过编译" << endl;
cin.get();
}
情况1:不能执行成功,类的析构函数就执行一次;
情况2:可以执行成功,类的析构函数就执行十次;
情况3:不能执行成功,没有执行类的析构函数;
·情况4:可以执行成功,类的析构函数就执行一次;
总结:如果是针对自定义的类对象指针的内存和开辟和释放(类中没有内存的开辟时),单个对象的内存的开辟必须用delete来释放,多个对象内存的开辟必须用delete[]来释放。
三、自定义的类对象指针的内存和开辟和释放(类中有内存的开辟)。
类的声明如下:
class CImage
{
public:
int width;
int height;
CImage(int w, int h);
CImage();
~CImage();
int * pImageData;
};
CImage::CImage()
{
pImageData = NULL;
cout << "构造函数2被执行" << endl;
}
CImage::CImage(int w, int h)
{
width = w;
height =h;
pImageData = new int[width*height];
cout << "构造函数1被执行" << endl;
}
CImage::~CImage()
{
if(pImageData != NULL)
{
cout << "对象内内存被释放" << endl;
delete[] pImageData;
pImageData = NULL;
}
cout << "析构函数被执行" << endl;
}
主函数如下:
{
//情况1
CImage* pImg = new CImage[11];
pImg[0].pImageData = new int [100];
pImg[2].pImageData = new int [100];
delete[] pImg;
//情况2
CImage* pImg = new CImage[11];
pImg[0].pImageData = new int [100];
pImg[2].pImageData = new int [100];
delete pImg;
//情况3
CImage* pImg = new CImage(3, 4);
pImg->pImageData = new int [100];
delete pImg;
//情况4
CImage* pImg = new CImage(3, 4);
pImg->pImageData = new int [100];
delete[] pImg;
}
情况1:可以执行,执行了十次构造函数,十次析构函数,同时pImg[0]和pImg[2]对象中pImageData的内存被释放。
情况2:不能执行成功,执行了十次构造函数,一次析构函数,程序停顿。
情况3:可移执行,执行了一次构造函数,一次析构函数,pImg对象中pImageData的内存被释放。
情况4:不能执行成功,执行了一次构造函数,程序停顿。
总结:如果是针对自定义的类对象指针的内存和开辟和释放(类中有内存的开辟时),单个对象的内存的开辟必须用delete来
释放,多个对象内存的开辟必须用delete[]来释放。注意:这种情况下,delete[]和delete都自动能调用类的析构函数,这样的话,
在类的析构函数中就需要添加释放对象中指针开辟内存的代码。
更近一步:针对下面两种情况都可以顺利执行:
//情况1
CImage* pImg = new CImage(3, 4);
pImg->pImageData = new int [100];
delete pImg->pImageData;
pImg->pImageData = NULL;
delete pImg;
//情况2
CImage* pImg = new CImage(3, 4);
pImg->pImageData = new int [100];
delete pImg;
情况1中,在释放pImg指针内存之前将其成员指针的内存先释放,这样不会有影响;情况2中直接释放pImg指针内存,这样,对象的析构函数会自
动被调用。但是:在情况2中,如果我们的析构函数中没有释放内存的语句,这种情况很容易造成内存泄漏。