vector 析构问题 (转)
(2012-10-02 10:28:27)
标签:
杂谈 |
请看下面的程序,说说会出现什么问题?
#include
#include
#include
using
namespace
std;
class
CDemo
{
public:
CDemo():str(NULL){};
~CDemo()
{
if(str)
delete[]
str;
};
char*
str;
};
int
main(int
argc,
char**
argv)
{
CDemo
d1;
d1.str=new
char[32];
strcpy(d1.str, "trend
micro");
vector
*a1=new
vector();
a1->push_back(d1);
delete
a1;
return
EXIT_SUCCESS;
}
这个程序在退出时,会出问题,什么问题?重复delete同一片内存,程序崩溃。
我们把析构函数改为如下,可以更清楚的看到这一点:
~CDemo()
{
if(str)
{
static int i=0;
cout<<"&CDemo"<<i++<<"="<<(int*)this<<",
str="<<(int *)str<<endl;
delete[]
str;
}
};
运行时我们发现打印如下信息:
&CDemo0=000309D8,
str=000307A8
&CDemo1=0013FF70,
str=000307A8
也就是说,发生了CDemo类的两次析构,两次析构str所指向的同一内存地址空间(两次str值相同=000307A8)。
为什么?
《程序员面试宝典》第二版,P99,有句解释“vector对象指针能够自动析构,所以不需要调用delete a1,否则会造成两次析构对象”
我切以为这句话说的有点不妥。任何对象如果是通过new操作符申请了空间,必须显示的调用delete来销毁这个对象。所以“delete
a1; ”这条语句是没有错误的。
这句话“vector
*a1=new vector(); ”定一个指针,指向
vector,病用new操作符进行了初始化,
我们必须在适当的时候释放a1所占的内存空间,所以“delete
a1; ”这句话是没有错误的。另外,我们必须明白一点,释放vector对象,vector所包含的元素也同时被释放。
那到底那里错误?
这句a1的声明和初始化语句“vector
*a1=new vector();
”说明a1所含元素是“CDemo”类型的,在执行“a1->push_back(d1);
”这条语句时,会调用CDemo的拷贝构造函数,虽然CDemo类中没有定义拷贝构造函数,但是编译器会为CDemo类构建一个默认的拷贝构造函数(浅拷贝),这就好像任何对象如果没有定义构造函数,编译器会构建一个默认的构造函数一样。
正是这里出了问题。a1中的所有CDemo元素的str成员变量没有初始化,只有一个四字节(32位机)指针空间。
“a1->push_back(d1);”这句话执行完后,a1里的CDemo元素与d1是不同的对象,但是a1里的CDemo元素的str与d1.str指向的是同一块内存,这从后来的打印信息就可以看出来。
我们知道,局部变量,如“CDemo d1; ”
在main函数退出时,自动释放所占内存空间,
那么会自动调用CDemo的析构函数“~CDeme”,问题就出在这里。
前面的“delete a1;”已经把 d1.str
释放了(因为a1里的CDemo元素的str与d1.str指向的是同一块内存),main函数退出时,又要释放已经释放掉的 d1.str
内存空间,所以程序最后崩溃。
解释清楚了。
这里最核心的问题归根结底就是浅拷贝和深拷贝的问题。如果CDemo类添加一个这样的拷贝构造函数就可以解决问题:
CDemo(const
CDemo
&cd)
{
this->str
=
new
char[strlen(cd.str)+1];
strcpy(str,cd.str);
#include
#include
#include
using
class
public:
};
int
}
这个程序在退出时,会出问题,什么问题?重复delete同一片内存,程序崩溃。
我们把析构函数改为如下,可以更清楚的看到这一点:
运行时我们发现打印如下信息:
&CDemo0=000309D8,
&CDemo1=0013FF70,
也就是说,发生了CDemo类的两次析构,两次析构str所指向的同一内存地址空间(两次str值相同=000307A8)。
为什么?
《程序员面试宝典》第二版,P99,有句解释“vector对象指针能够自动析构,所以不需要调用delete a1,否则会造成两次析构对象”
我切以为这句话说的有点不妥。任何对象如果是通过new操作符申请了空间,必须显示的调用delete来销毁这个对象。所以“delete
这句话“vector
那到底那里错误?
这句a1的声明和初始化语句“vector
正是这里出了问题。a1中的所有CDemo元素的str成员变量没有初始化,只有一个四字节(32位机)指针空间。
“a1->push_back(d1);”这句话执行完后,a1里的CDemo元素与d1是不同的对象,但是a1里的CDemo元素的str与d1.str指向的是同一块内存,这从后来的打印信息就可以看出来。
我们知道,局部变量,如“CDemo
那么会自动调用CDemo的析构函数“~CDeme”,问题就出在这里。
前面的“delete
解释清楚了。
这里最核心的问题归根结底就是浅拷贝和深拷贝的问题。如果CDemo类添加一个这样的拷贝构造函数就可以解决问题:

加载中…