如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省拷贝构造函数和赋值函数。
倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。
以类String的两个对象a,b为例,假设a.m_data的内容为“hello”,b.m_data的内容为“world”。 现将a赋给b,缺省赋值函数的“位拷贝”意味着执行b.m_data = a.m_data。这将造成三个错误:
1>b.m_data原有的内存没被释放,造成内存泄露;
2>b.m_data和a.m_data指向同一块内存,a或b任何一方变动都会影响另一方;
3>在对象被析构时,m_data被释放了两次
// 赋值函数
String & String::operate =(const String &other)
{
// (1) 检查自赋值,防止自己赋值给自己
if(this == &other)
return *this;
// (2) 释放原有的内存资源
delete [] m_data;
// (3)分配新的内存资源,并复制内容
int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data, other.m_data);
// (4)返回本对象的引用
return *this;
}
浅拷贝(即系统提供的拷贝构造函数):
浅拷贝,也就是按照比特一位一位地进行拷贝,是把一个类完全一样拷贝到另一个类
深拷贝(即自己定义的拷贝构造函数):
在一个类中,假设有一个指向一个Buffer的指针,所以我们可以说这个指针指向了一个资源(这个资源可以是一块保存数据的内存)如果这时用浅拷贝即系统提供的默认的拷贝构造函数,这时就出现问题了:因类类内部的指针的值是一样的,也就是说,两个类的实例内部的指针指向了同一块内存。当这两个对象析构的时候,同一块内存就会给析构两次,当然会出现问题,深拷贝,就是在这点上和浅拷贝不同的,也就是说,在拷贝的时候,深拷贝会提供一块新的内存用来保存数据,并使新的对象的指针指向这块内存,这两个对象析构的时候,也就不会把同一块内存析构两次了,如下String类自己定义的拷贝构造函数:
// 拷贝构造函数
String::String(const String &other)
{
// 允许操作other的私有成员m_data
int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data, other.m_data);
}
拷贝构造函数与赋值函数的区别:
拷贝构造函数就是用一个己经构造好的对象来初始化一块新的内存区域,这块内存区域就是放新对象的内存区域,如:
class A{...};
A a1;
A a2 = a1; //a2是新构造的内存区域,现在调用拷贝构造用己经构造好的a1来初始化a2的新的内存区域
A a3(a1);
赋值函数就是用一个己经构造好的对象来初始化另一个己经构造好的对象,这块内存区域之前就己经开辟好了,如下,(所有看上面的String的赋值函数,里面先作释放原有的内存资源( delete [] m_data;)这个动作,是为了防止内存泄漏,而拷贝构造函数就不需要.因为他是新开辟的内存区域,无需释放.
A a1;
A a2;
a2 = a1;
转至http://blog.sina.com.cn/s/blog_5fa144950100kic5.html