拷贝构造函数和赋值操作符

如果有一个例如以下的MyClass类:

class MyClass
{
public:
	//构造函数
	//拷贝构造函数
	MyClass(const MyClass& that)
		: int_data_(that.int_data_),
		  dbl_data_(that.dbl_data_),
		  str_data_(that.str_data_)
	{
	}
	//赋值操作符
	MyClass& operator = (const MyClass& that)
	{
		if(this != that)
		{
			int_data_ = that.int_data_;
			dbl_data_ = that.dbl_data_;
			str_data_ = that.str_data_;
		}
		return *this;
	}

	//一些其它方法
private:
	Int int_data_;
	Double dbl_data_;
	string str_data_;
	//每次在这里加入一个新的数据成员时,不要忘了在拷贝构造函数和赋值操作中加入相应的代码
};

对于这个类,存在什么问题呢?真正的问题是,在私有部分后面的凝视指出了问题的所在。假设像凝视中所说的,这种操作特别麻烦并且极易犯错误。其实,假设我们没有编写拷贝构造函数和赋值操作符,C++会为我们编写一个“默认版本号”。

拷贝构造函数的默认版本号为全部的数据成员调用拷贝构造函数(或简单的复制内置类型),赋值操作符的默认版本号将调用每一个数据成员的赋值操作符或者简单的复制内置类型。

因此,对于上面的样例,拷贝构造函数和赋值操作符全然没必要的。更糟的是,它们是潜在的错误之源,由于它们使代码变得脆弱。假设有人试图改变它们,就可能对代码产生破坏。

因此,对于上述的样例,比較好的思路是彻底避免编写拷贝构造函数和赋值操作符。

一般而言,有几种方式可供选择:

  • 依赖编译器自己主动创建的默认版本号
  • 把拷贝构造函数和赋值操作符声明为私有,而且不提供实现,禁止不论什么类型的复制
  • 编写自己的版本号
对于上述三种方式,应该尽量避免使用第三种。假设发现自己为某个类编写了拷贝构造函数或赋值操作符,思考是否有必要。或许能够避免这样的做法并转为第一种方式(使用编译器所创建的默认版本号)或使用其它方法(比如智能指针)。假设仍然不确定,能够使用另外一种方式,仅仅要不存在不论什么类型的复制,就不会出错。可是,须要注意类的有些使用方法(比如在vector<MyClass>中)须要拷贝构造函数和赋值操作符,因此禁止不论什么类型的复制也须要慎重,必须理解它限制了类的使用方面的某些选项。

总结:

  • 仅仅要有可能,避免编写拷贝构造函数和赋值操作符
  • 假设默认版本号并不适用,能够考虑把拷贝构造函数和赋值操作符声明为私有,禁止类实例的复制

posted @ 2015-03-11 15:18  blfshiye  阅读(312)  评论(0编辑  收藏  举报