Boost程序库完全开发指南:深入C++”准”标准库(第5版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

4.1 noncopyable

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

noncopyable位于名字空间boost,需要包含的头文件如下noncopyable的真正实现源码位于<boost/core/noncopyable.hpp>。

#include<boost/noncopyable.hpp>

4.1.1 原理

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

例如:

class empty_class {};

对于这样一个简单的“空”类Boost在头文件<boost/blank.hpp>定义了一个有用的空类blank,支持比较和流输出。,编译器在处理它时会“默默地”为它增加拷贝构造函数和拷贝赋值操作符,真实代码类似于:

一般情况下这种操作是有用的,比如可以自动支持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是定义在子名字空间boost::noncopyable_里,并且使用了条件编译宏。

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

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