类的动态内存分配 和复制构造函数

class class_base
{
	int* pt;
public:
	class_base(int);//构造函数
	class_base(const class_base&);//复制构造函数
	virtual void show_info();
	virtual ~class_base();//析构函数
};

举例所用的类class_base如上面所示,具体的定义下面会给出。如果类的数据成员中使用了动态内存分配(如上面的int* pt;),则必须要显式的定义复制构造函数,重载赋值运算符,和析构函数。原因很简单,首先来说构造函数。如果不显式的定义复制构造函数而是使用默认的版本,则只会简单的复制类的数据成员,包括指针。如果执行下述代码

int main()
{
	class_base *pt_1;
	pt_1 = new class_base(1);
	class_base *pt_2;
	pt_2 = new class_base(*pt_1);
}

类对象*pt_1和*pt_2的数据成员pt_1->pt,pt_1->pt是完全相同的,即指针地址相同,或者说两个指针指向了同一片内存。如果类对象*pt_1的生命周期结束,则其析构函数会被调用,指针pt指向的内存也随之被释放(这里也是为何需要显式定义析构函数的原因,如果不显式定义,只是简单释放所有数据成员,即把指针pt的值清理了,但pt所指向的内存却依然存在,并且,随着指针的被清理,内存变成了无法访问无法寻找的内存。因此,在析构函数中必须使用delete关键字把动态分配的内存释放掉)。等一下,pt_2的生命周期没有结束,但pt_2->pt指向的内存却被释放了? 显然这是矛盾的,因此我们需要显式的定义复制构造函数。代码如下
class_base::class_base(int vl)
{
	pt = new int(vl);
}
class_base::class_base(const class_base& cb)//显示
{
	pt = new int(*(cb.pt));
}
void class_base::show_info()
{
	cout << *pt << endl;
}
class_base::~class_base()
{
	delete pt;
}
显然,在调用复制构造函数的时候,为新生成的对象的数据成员动态分配了新的内存,然后把这块内存设置成与被复制对象相同的值或者状态。下面调用代码进行测试。

int main()
{
	class_base *pt_1;
	pt_1 = new class_base(1);
	class_base *pt_2;
	pt_2 = new class_base(*pt_1);
	pt_1->show_info();
	pt_2->show_info();
	delete pt_1;
	pt_2->show_info();
	system("pause");
	delete pt_2;
	return 0;
}
可以正常输出,结果如下图所示

类的动态内存分配 和复制构造函数_第1张图片
如果此时我们对类方法的进行修改,去掉显式的复制构造函数,而是使用默认版本的,结果如下

类的动态内存分配 和复制构造函数_第2张图片

为什么会出现这个结果呢,原因很简单,像上面所说的,两个对象*pt_1,*pt_2的成员完全相同,其中一个被delete了,则另一个的成员指针指向的内存被释放掉了,你再用这个指针去访问一片被delete的内存,显然得不到你想得到的东西~

你可能感兴趣的:(类的动态内存分配 和复制构造函数)