4.1 noncopyable
noncopyable允许程序轻松地实现一个禁止拷贝的类。
noncopyable位于名字空间boost,需要包含的头文件如下:
#include<boost/noncopyable.hpp>
4.1.1 原理
在C++中定义一个类时,如果不明确定义拷贝构造函数和拷贝赋值操作符,编译器会为我们自动生成这两个函数。
例如:
class empty_class {};
对于这样一个简单的“空”类,编译器在处理它时会“默默地”为它增加拷贝构造函数和拷贝赋值操作符,真实代码类似于:
一般情况下这种操作是有用的,比如可以自动支持swap()、符合容器的拷贝语义、可以放入标准容器处理,但有的时候我们不需要类的拷贝语义,希望禁止拷贝实例。
这是一个很经典的C++惯用法,其原理很好理解,只需要“私有化”拷贝构造函数和拷贝赋值操作符即可,手写代码也很简单(3.2节的scoped_ptr就使用了这个惯用法)。例如:
但如果程序中有大量这样的类,重复这样的代码是相当乏味的,而且代码出现的次数越多,越容易增加手写代码出错的概率。虽然也可以用带参数的宏来减少重复,但这种解决方案不够“优雅”。
4.1.2 用法
noncopyable为实现不可拷贝的类提供了简单清晰的解决方案:从boost::noncopyable派生即可。
使用noncopyable,上面的例子可简化为
我们也可以显式地写出private或public修饰词,但其效果是相同的。因此直接这样写可以少输入一些代码,也更清晰,并且表明了HAS-A关系(而不是IS-A关系)。
如果有其他人误写了代码(很可能是没有仔细阅读接口文档),企图拷贝构造或赋值这个对象,那么其操作将不能通过编译器的审查:
使用GCC编译会报出类似下面的错误提示:
error:use of deleted function'boost::noncopyable_...'
这条错误信息明确地告诉我们:类使用boost::noncopyable禁用(delete)了拷贝构造,无法调用拷贝构造函数。
只要有可能,就使用boost::noncopyable,它明确无误地表达了类设计者的意图,对用户更加友好,而且与其他Boost库也配合得很好。
4.1.3 实现
noncopyable的实现原理很简单,代码很少:
因此,当我们的自定义类是noncopyable的子类时,就会自动私有化父类noncopyable的拷贝构造函数,从而禁止用户从外部访问拷贝构造函数和拷贝赋值函数。
如果使用新的default和delete关键字,则noncopyable可以更清晰地实现: