类的复制控制之关键
cugwhp opened this issue · comments
Introduction
类的复制控制(C++Primer 4th)在Ch14th中有专门的介绍。简而言之,就是通过同类对象的引用,克隆一个与之相同的副本对象出来。在克隆的时候,对于简单的变量,或者已经定义好了复制控制的对象,克隆是可以正确复制,但对于没有指定复制控制的变量,尤其是new的指针,就没法正确复制了,此时就需要类自定义复制控制的函数,包括:拷贝构造函数、operator=和析构函数。
Questions
1. 若类中没有定义复制控制的函数,会出现什么情况?
没有定义复制控制函数的类,在编译时,编译器会自动加上合成的复制控制函数。示例代码如下:
// 未定义复制控制函数的版本
class B{
int m;
};
// 合成复制控制函数的版本
class B{
public:
B(){} //构造函数
B(const B& b) : m(b.m){} //拷贝构造函数
B& operator=(const B& b){m=b.m; return *this} //赋值函数
~B(){} //析构函数
int m;
};
对于成员变量简单的类,合成函数处理起来就足以了。试想,如果class B中有个指针定义int* ptM的成员变量的话,这个合成的代码会不会有问题呢?
很显然,会有问题,示例代码如下:
// 包含指针变量的类的合成复制控制函数的版本
class B{
public:
B(){}
B(const B& b) : m(b.m), ptM(b.ptM){}
B& operator=(const B& b){m=b.m; ptM=b.ptM; return *this}
~B(){}
int m; //数值个数
int* ptM; //数组地址
};
试想这样的合成函数能解决问题吗??
显然是不能的,因为复制控制的函数,并没有深度拷贝指针(地址)所指向的实际内容,只是复制了指针的地址,这样的浅层拷贝,非常容易引发指针指向内容已经不在作用域里的情况。那么如何解决这个问题呢,只有自己改,那就只能自己深度copy。
// 包含指针变量的类的合成复制控制函数的版本
class B{
public:
B(){}
B(const B& b) : m(b.m){
ptM=new int[b.m];
memcpy(ptM, b.ptM, sizeof(int)*m);
}
B& operator=(const B& b){
if (this == &b)
return *this;
m=b.m;
if (ptM) delete[] ptM;
ptM=new int[m];
memcpy(ptM, b.ptM, sizeof(int)*m);
return *this
}
~B(){
if (ptM){
delete[] ptM;
}
}
int m; //数值个数
int* ptM; //数组地址
};