Boost开发指南-4.1noncopyable

noncopyable

noncopyable 允许程序轻松地实现一个禁止拷贝的类。

noncopyable位于名字空间boost,为了使用noncopyable 组件,需要包含头文件<boost/noncopyable.hpp>或者<boost/utility.hpp>(后者包含了数个小工具的实现):

#include <boost/noncopyable.hpp> //或者
#include <boost/utility.hpp> 

原理

在C++中定义一个类时,如果不明确定义拷贝构造函数和拷贝赋值操作符,编译器会为我们自动生成这两个函数。

例如:

class empty_class();

这样一个简单的“空”类R,编译器在处理时会“默默地”为它增加拷贝构造函数和拷贝赋值操作符,真实代码类似于:

class empty_class
{
    
    
public: //构造和析构暂时忽略
   empty_class (const empty_class &){
    
    ...} //拷贝构造函数
   empty_class & operator=(const empty_class &){
    
    ...} //拷贝赋值
};

一般情况下这是有用的,比如可以自动支持swap()、符合容器的拷贝语义、可以放入标准容器处理,但有的时候我们不需要类的拷贝语义,希望禁止拷贝类的实例。

这是一个很经典的c++惯用法,原理很好理解,只需要私有化拷贝构造函数和拷贝赋值操作符即可,手写代码也很简单(scoped_ptr就使用了这个惯用法),例如:

class do_not_copy
{
    
    
private:
   do_not_copy (const do_not_copy &); //私有化,声明即可,不需要实现代码
   void operator=(const do_not_copy &); //私有化,声明即可,不需要实现代码
};

但如果程序中有大量这样的类,重复写这样的代码是相当乏味的,而且代码出现的次数越多越容易增大手写出错的几率。虽然也可以用带参数的宏来减少重复,但解决方案不够优雅。

用法

noncopyable为实现不可拷贝的类提供了简单清晰的解决方案:从boost::noncopyable派生即可。

使用noncopyable,上面的例子可简化为:

#include <boost/noncopyable.hpp>
class do_not_copy: boost::noncopyable
{
    
    ...};

注意,这里使用缺省的私有继承是允许的。我们也可以显式写出 private或者public修饰词,但效果是相同的。因此直接这样写少输入了一些代码,也更清晰,并且表明了HAS-A关系(而不是工S-A)。

如果有其他人误写了代码(很可能是没有仔细阅读接口文档),企图拷贝构造或者赋值do_not_copy,那么将不能通过编译器的审查:

do_not_copy d1; //一个不可拷贝对象
do_not_copy d2(d1); //企图拷贝构造,编译出错
do_not_copy d3; //另一个不可拷贝对象
d3 = d1; //企图拷贝赋值,编译出错

使用GCC编译会报出类似下面的错误提示:

note: 'do_not_copy::do_not_copy(const do_not_copy&)'
is implicitly deleted because the default definition would be ill-formed:
class do_not_copy: boost::noncopyable
error: use of deleted function 'boost::noncopyable_ ...'

这条错误信息明确地告诉我们:类使用boost::noncopyable禁用(delete)了拷贝构造,无法调用拷贝构造函数。

只要有可能,就使用boost::noncopyable,它明确无误地表达了类设计者的意图,对用户更加友好,而且与其他Boost库也配合得很好。

实现

class noncopyable
{
    
    
protected:
   noncopyable() {
    
    }
   ~noncopyable() {
    
    }
private:
   noncopyable (const noncopyable&); //私有化拷贝构造和拷贝赋值
   const noncopyable& operator=(const noncopyable&);
};

因此,当我们的自定义类是noncopyable的子类时就会自动私有化父类noncopyable的拷贝构造函数,从而禁止用户从外部访问拷贝构造函数和拷贝赋值函数。

如果使用C++11标准的新default和 delete关键字,则noncopyable可以更清晰地实现如下:

class noncopyable
{
    
    
protected:
    noncopyable() = default; //默认的构造和析构是保护的
    ~noncopyable() = default; //使用默认实现
    //使用delete关键字禁用拷贝构造和拷贝赋值
    noncopyable(const noncopyable&) = delete;
    const noncopyable& operator=(const noncopyable&) = delete;
};

代码示例

#include <iostream>
using namespace std;

#include <boost/noncopyable.hpp>

//
class do_not_copy : boost::noncopyable
{
    
    };

//


int main()
{
    
    
	do_not_copy d1;
	//do_not_copy d2(d1);
	//do_not_copy d3;
	//d3 = d1;
}

猜你喜欢

转载自blog.csdn.net/qq_36314864/article/details/132097951
今日推荐