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