跳转至内容

更多 C++ 惯用法/不可复制 Mixin

来自 Wikibooks,开放世界中的开放书籍

不可复制 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);
}

已知用途

[编辑 | 编辑源代码]

boost::noncopyable

[编辑 | 编辑源代码]

奇怪的递归模板模式

参考文献

[编辑 | 编辑源代码]
  1. ISO/IEC 14882:2003 C++ 标准 §12.8/4,§12.8/7
华夏公益教科书