cugwhp / OOPCPP

Learn C++ Programming Language

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

类的复制控制之关键

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;	//数组地址
};