更多 C++ 惯用法/不可复制 Mixin
外观
防止类的对象被复制构造或相互赋值。
很多时候,阻止复制类的对象是有意义的。例如,一个封装网络连接的类。对于这样的类,复制无法有意义地定义。因此,应该明确地阻止它,而不依赖于指南或程序员的纪律。意图也应该通过查看类的声明来轻松识别,以提高可读性。
定义了一个名为 non-copyable 的类,它具有私有复制构造函数和复制赋值运算符。
class NonCopyable
{
public:
NonCopyable (const NonCopyable &) = delete;
NonCopyable & operator = (const NonCopyable &) = delete;
protected:
NonCopyable () = default;
~NonCopyable () = default; /// Protected non-virtual destructor
};
class CantCopy : private NonCopyable
{};
CantCopy 对象无法复制,因为私有基类 NonCopyable 的复制构造函数和复制赋值运算符对派生类不可访问。处理这些的传统方法是声明一个私有复制构造函数和复制赋值,然后记录为什么要这样做。但是从 noncopyable 派生更简单、更清晰,并且不需要额外的文档。NonCopyable 的私有成员不需要定义。NonCopyable 也可以归类为自上而下的 mixin,因为它定义了一个可重复使用的模块,该模块从“上方”将“不可复制性”功能“混合”到派生类中。CRTP 解决方案如下。(这允许在多重继承中进行空基优化 [参见讨论页])。
template <class T>
class NonCopyable
{
public:
NonCopyable (const NonCopyable &) = delete;
T & operator = (const T &) = delete;
protected:
NonCopyable () = default;
~NonCopyable () = default; /// Protected non-virtual destructor
};
class CantCopy : private NonCopyable <CantCopy>
{};
显式复制构造函数
值得注意的是,C++ 允许另一种方法来控制复制构造。一个显式复制构造函数将阻止编译器隐式调用复制构造函数。即,按值传递对象和按值返回对象将被禁用,因为具有显式复制构造函数的类。但是,允许进行显式复制。在 gcc 上,使用 -fno-elide-constructors 选项禁用复制消除。此选项有助于观察(实际上并未观察!)返回值优化的效果。通常不建议禁用此重要的优化。
struct NoImplicitCopy
{
NoImplicitCopy () = default;
explicit NoImplicitCopy (const NoImplicitCopy &) = default;
};
NoImplicitCopy foo() // Compiler error because copy-constructor must be invoked implicitly to return by value.
{
NoImplicitCopy n;
return n;
}
void bar(NoImplicitCopy n) // Compiler error because copy-constructor must be invoked implicitly to pass by value.
{
}
int main(void)
{
NoImplicitCopy n;
NoImplicitCopy x(n); // This is fine. explicit copy.
n = foo();
bar(n);
}
- ISO/IEC 14882:2003 C++ 标准 §12.8/4,§12.8/7