如何使此C++对象不可复制?

ano*_*non 64 c++ copy-constructor noncopyable

见标题.

我有:

class Foo {
   private:
     Foo();
   public:
     static Foo* create();
}
Run Code Online (Sandbox Code Playgroud)

我需要做什么才能让Foo无法复制?

谢谢!

Kla*_*aim 89

class Foo {
   private:
     Foo();
     Foo( const Foo& ); // non construction-copyable
     Foo& operator=( const Foo& ); // non copyable
   public:
     static Foo* create();
}
Run Code Online (Sandbox Code Playgroud)

如果你正在使用boost,你也可以从noncopyable继承:http://www.boost.org/doc/libs/1_41_0/boost/noncopyable.hpp

编辑:C++ 11版本,如果您有一个支持此功能的编译器:

class Foo {
   private:
     Foo();
     Foo( const Foo& ) = delete; // non construction-copyable
     Foo& operator=( const Foo& ) = delete; // non copyable
   public:
     static Foo* create();
}
Run Code Online (Sandbox Code Playgroud)

  • 禁用复制构造和复制赋值运算符也会禁用移动构造和赋值.通过回退复制,移动操作仍将起作用.通过明确将它们设置为"默认"来重新启用它们.需要注意的事情. (6认同)
  • 将删除的方法放入公共部分是一个很好的做法。 (4认同)
  • 有兴趣的是,为什么要将默认的构造函数设为私有,并添加create()方法?这种布局有什么优势? (2认同)

Han*_*ant 25

使复制构造函数和赋值运算符也是私有的.只需声明即可,您无需提供实施.


yes*_*aaj 18

另一种禁止复制构造函数的方法,为方便起见,可以使用DISALLOW_COPY_AND_ASSIGN宏:

// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
  TypeName(const TypeName&) = delete;      \
  void operator=(const TypeName&) = delete
Run Code Online (Sandbox Code Playgroud)

然后,在Foo类中:

class Foo {
 public:
  Foo(int f);
  ~Foo();

 private:
  DISALLOW_COPY_AND_ASSIGN(Foo);
};
Run Code Online (Sandbox Code Playgroud)

来自谷歌样式表的参考

  • @ThreeBit:你指的是哪些编译器?如果他们这样做,他们就不符合标准。 (2认同)
  • @ThreeBit:有趣的讨论。我在标准中发现的内容:_“程序中应**至多**一个非内联成员函数的定义;不需要诊断。”_。然后,对于本地类:_“本地类的成员函数应在它们的类定义中内联定义,**如果它们被定义了。**”_。我没有发现任何禁止没有相应定义的成员函数声明的内容。 (2认同)

Chr*_*s H 17

#include <boost/utility.hpp>
class Foo : boost::noncopyable {...
Run Code Online (Sandbox Code Playgroud)

但正如斯科特迈尔斯曾经说过的那样......"这是一个很好的课程,只是我发现这个名字有点不合适,不自然",或类似的东西.

  • 参考:有效的C++(第三版) - Scott Meyers,第6项 (4认同)

Mat*_* M. 17

在那里添加一点.

传统的解决方案是,正如人们所说的,要宣布双方Copy ConstructorAssignment Operator作为private,而不是定义它们.

  • 因为它们private会导致编译时出错,任何试图使用它们的人都无法访问该类的私有部分...
  • 这会undefined symbol链接时(或者在那里检查那些)或者最有可能在运行时(当尝试加载库时)以形式发生错误的朋友(以及类本身).

当然,在第二种情况下是非常麻烦的,因为您必须自己检查代码,因为您没有指示发生错误的文件和行.幸运的是,它只限于你的班级方法和朋友.


此外,值得注意的是,这些属性在继承和组合之路上是传递的:编译器只生成Default Constructorthe Copy Constructor,the Assignment Operator和the Destructorif的默认版本.

这意味着对于这四个中的任何一个,只有当它们可以访问类的所有基础和属性时,它们才会自动生成.

// What does boost::noncopyable looks like >
class Uncopyable {
public:
  Uncopyable() {}

private:
  Uncopyable(const Uncopyable&);
  Uncopyable& operator=(const Uncopyable&);
};
Run Code Online (Sandbox Code Playgroud)

这就是为什么从这个类继承(或者使用它作为属性)将有效地防止你自己的类可以被复制或分配,除非你自己定义这些运算符.

一般来说,选择继承是因为组合有两个原因:

  • Uncopyable即使多态性可能没那么有用,该对象也是有效的
  • 继承导致EBOor Empty Base Optimization,虽然属性是可寻址的,因此将占用内存(在类的每个实例中),即使它实际上不需要它,编译器也有可能不为基类添加这种开销.

或者,您可以将运算符声明为私有而不是在您自己的类中定义它们,但代码将不那么自我记录,并且您将无法自动搜索那些具有此属性的类(除非您有完整的解析器).

希望这能为机制提供一些启示.


bob*_*uba 11

在C++ 11中,您可以通过放置= delete声明后显式禁用默认副本和赋值构造函数的创建.

来自维基百科:

struct NonCopyable {
    NonCopyable() = default;
    NonCopyable(const NonCopyable&) = delete;
    NonCopyable & operator=(const NonCopyable&) = delete;
};
Run Code Online (Sandbox Code Playgroud)

课程也是如此.


jam*_*lin 5

使 C++ 对象不可复制的典型方法是显式声明复制构造函数和复制赋值运算符,但不实现它们。这将阻止编译器生成自己的。(通常,这与声明它们一起完成,private以便生成编译错误而不是链接器错误。)

还有boost::noncopyable一个可以继承的类,它执行我上面描述的操作。


Mat*_*her 5

C++11 中的良好实践是将复制构造函数和赋值声明为公开删除。不是私下删除,公开删除:https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-delete