boost::noncopyable 禁止拷贝

boost::noncopyable 禁止拷贝

当我们定义一个类时,我们显示地或隐式地指定在此类型的对象拷贝、移动、赋值和销毁时做什么。一个类通过定义五种特殊的成员函数来控制这些操作,包括:拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符和析构函数。我们称这些操作作为拷贝控制操作。

如果一个类没有定义所有的这些拷贝控制成员,编译器会自动为它定义缺失的操作。很多类会忽略这些拷贝控制操作。但是,对一些类来说,依赖这些操作的默认设定会导致灾难。

有时候,当我们定义某个类时,我们可能不希望我们定义的类进行拷贝操作。为此,我们可以采用将拷贝构造和拷贝赋值声明为PRivate(私有)的,这样的话就能禁止类进行拷贝操作。不过,这样做的话,显得比较麻烦。为此,boost中就提供noncopyable,我们通过继承noncopyable就可以实现禁止拷贝了。

下面是boost::noncopyable类的实现。在实现中,将构造函数和析构函数声明为保护,这样不会影响noncopyable作为基类,也避免外部构建一个noncopyable实类。

namespace noncopyable_  // protection from unintended ADL
{
	class noncopyable 
	{ 
	protected: 
		noncopyable() {} 
		~noncopyable() {} 
	
	private: 
		// emphasize the following members are private 
		noncopyable( const noncopyable& ); 
		noncopyable& Operator=( const noncopyable& ); 
	};
	
	typedef noncopyable_::noncopyable noncopyable;
}; 

 那么,问题来了。为什么将noncopyable作为基类,能使派生类实现禁止拷贝? 这是因为,在派生类拷贝过程中,主要分为2部分:首先,调用基类的复制构造函数完成基类部分的复制,然后再复制派生类的部分。由于基类的拷贝构造函数和拷贝赋值运算符声明为私有的,派生类无法访问。所以,在第一部分的时候已经失败了,这就成功的禁止派生类的拷贝功能。

我们可以尝试写如下的测试代码,编译环境VS2013。

当我们未使用boost::noncopyable时:

class MyClass 
{
public:
	MyClass()  {}
	~MyClass() {}
};

int main(void)
{
	MyClass CMySrc;
	MyClass CMyDest;
	MyClass CMyDest1(CMySrc);

	CMyDest = CMySrc;

	return 0;
}

此时,编译成功。

当我们使用boost::noncopyable时:

#include <boost/noncopyable.hpp>

class MyClass   :  public boost::noncopyable
{
public:
	MyClass()  {}
	~MyClass() {}
};

int main(void)
{
	MyClass CMySrc;
	MyClass CMyDest;
	MyClass CMyDest1(CMySrc);	//错误

	CMyDest = CMySrc;		//错误

	return 0;
}此时,编译不通过。说明确实禁止了类的拷贝功能。