c++中私有拷贝构造函数有什么用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6811037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:42:24  来源:igfitidea点击:

What's the use of the private copy constructor in c++

c++copy-constructorassignment-operator

提问by

Why do people define a private copy constructor?

人们为什么要定义私有复制构造函数?

When is making the copy constructor and the assignment operator private a good design?

何时将复制构造函数和赋值运算符设为私有是一个好的设计?

If there are no members in the class which are pointers or handles to a unique object (like file name), then wat other cases are there where private copy constructor is a good idea?

如果类中没有成员是指向唯一对象(如文件名)的指针或句柄,那么在其他情况下,私有复制构造函数是个好主意吗?

Same question apply for assignment operator. Given that majority of C++ revolves around copying of objects and passing by reference, are there any good designs which involve private copy constructor?

同样的问题适用于赋值运算符。鉴于大多数 C++ 都围绕对象的复制和通过引用传递,是否有涉及私有复制构造函数的好的设计?

采纳答案by Tony Delroy

Some objects represent particular entities that can't or shouldn't be copied. For example, you may prevent copying of an object that represents the log file used by an application, corresponding to the expectation that a single log file will be used by all parts of the code. Use of an accidentally or inappropriately copied object could lead to out-of-order content appearing in the log, inaccurate records of current log size, multiple attempts (some failing) to "roll" to a new log filename or rename the existing one.

某些对象代表不能或不应复制的特定实体。例如,您可以阻止复制代表应用程序使用的日志文件的对象,这对应于代码的所有部分都将使用单个日志文件的期望。使用意外或不当复制的对象可能会导致日志中出现乱序内容、当前日志大小记录不准确、多次尝试(有些失败)“滚动”到新日志文件名或重命名现有文件名。

Another use is to enforce copying via a virtual function. As constructors can't be virtual, a common practice is to prevent direct access to the copy constructor and provide a virtual Base* clone()method that returns a copy of the actual run-time type to which a pointer points. This prevents the accidental slicing that Base b(derived)would exhibit.

另一个用途是通过虚函数强制复制。由于构造函数不能virtual,所以通常的做法是防止直接访问复制构造函数并提供一种virtual Base* clone()方法,该方法返回指针指向的实际运行时类型的副本。这可以防止Base b(derived)可能出现的意外切片。

Another example: a dead-simple smart pointer object that simply deletes the pointer it's given in the constructor: if it doesn't support reference counting or some other manner of handling multiple owners, and doesn't want to have risk awkward unintended std::auto_ptrstyle transfer of ownership, then simply hiding the copy constructor gives a great little smart pointer that's fast and efficient for the limited cases where it's usable. A compile time error about attempting to copy it would effectively ask the programmer "hey - if you really want to do that change me to a shared pointer, otherwise back off!".

另一个例子:一个非常简单的智能指针对象,它只是删除它在构造函数中给出的指针:如果它不支持引用计数或其他处理多个所有者的方式,并且不想冒尴尬的意外std::auto_ptr样式转移的风险所有权,然后简单地隐藏复制构造函数提供了一个很棒的小智能指针,它在可用的有限情况下快速有效。关于尝试复制它的编译时错误会有效地询问程序员“嘿 - 如果你真的想这样做,请将我更改为共享指针,否则退后!”。

回答by Eric Z

One use case is the singleton patternwhere there can only be exactly one instance of a class. In this case, you need make your constructors and assignment operator= private so that there is no way of creating more than one object. The only way to create an object is via your GetInstance() function as shown below.

一个用例是单例模式,其中一个类只能有一个实例。在这种情况下,您需要将构造函数和赋值 operator= 设为私有,这样就无法创建多个对象。创建对象的唯一方法是通过 GetInstance() 函数,如下所示。

// An example of singleton pattern
class CMySingleton
{
public:
  static CMySingleton& GetInstance()
  {
    static CMySingleton singleton;
    return singleton;
  }

// Other non-static member functions
private:
  CMySingleton() {}                                  // Private constructor
  ~CMySingleton() {}
  CMySingleton(const CMySingleton&);                 // Prevent copy-construction
  CMySingleton& operator=(const CMySingleton&);      // Prevent assignment
};

int main(int argc, char* argv[])
{
  // create a single instance of the class
  CMySingleton &object = CMySingleton::GetInstance();

  // compile fail due to private constructor
  CMySingleton object1;
  // compile fail due to private copy constructor
  CMySingleton object2(object);
  // compile fail due to private assignment operator
  object1 = object;

  // ..
  return 0;
}

回答by tc.

A very bad example:

一个非常糟糕的例子:

class Vehicle : { int wheels; Vehicle(int w) : wheels(w) {} }

class Car : public Vehicle { Engine * engine; public Car(Engine * e) : Vehicle(4), engine(e) }

...

Car c(new Engine());

Car c2(c); // Now both cars share the same engine!

Vehicle v;
v = c; // This doesn't even make any sense; all you have is a Vehicle with 4 wheels but no engine.

What does it mean to "copy" a car? (Is a car a car model, or an instance of a car? Does copying it preserve the vehicle registration?)

“复制”汽车是什么意思?(汽车是汽车模型还是汽车的实例?复制它会保留车辆登记吗?)

What does it mean to assign a vehicle to another one?

将一辆车分配给另一辆车是什么意思?

If the operations are meaningless (or merely unimplemented), the standard thing to do is to make the copy constructor and assignment operator private, causing a compile error if they're used instead of weird behaviour.

如果操作毫无意义(或只是未实现),那么标准的做法是将复制构造函数和赋值运算符设为私有,如果使用它们而不是奇怪的行为,则会导致编译错误。

回答by user396672

A common reason to make copy constructor and copy assignment private is to disable default implementation of these operations. However, in C++ 0x there are special syntax =deletefor such purpose. So in C++ 0x making copy ctor private seems to be resrtricted to very exotic cases.

将复制构造函数和复制赋值设为私有的一个常见原因是禁用这些操作的默认实现。但是,在 C++ 0x 中有特殊语法 = delete用于此目的。因此,在 C++ 0x 中,将复制 ctor 设为私有似乎仅限于非常奇特的情况。

Copy ctors and assignments are rather syntactic sugar; so such a "private sugar" seems as symptom of greed :)

复制构造函数和赋值是相当语法糖;所以这样的“私人糖”似乎是贪婪的症状:)

回答by Nicol Bolas

Even if the contents of the object aren't pointers or other references, preventing people from copying the object can still be useful. Perhaps the class contains a lot of data, and copying is too heavyweight of an operation.

即使对象的内容不是指针或其他引用,防止人们复制对象仍然很有用。也许这个类包含很多数据,复制是一个太重量级的操作。

回答by Petar Ivanov

You might want to implement some of the methods of the class using a copy constructor, but not to expose it outside of the class. So then you make it private. Like any other method.

您可能希望使用复制构造函数实现类的某些方法,但不要将其暴露在类之外。然后你把它设为私有。像任何其他方法一样。

回答by J T

The "virtual constructor idiom" is an important case where a private or protected copy constructor is needed. A problem arises in C++ where you are given the pointer to a base class, of an object that is actually inherited from this base class, and you want to make a copy of it. Calling the copy constructor would not call the copy constructor of the inheriting class, but actually call the copy constructor of the base class.

虚拟构造函数习惯用法”是需要私有或受保护的复制构造函数的重要情况。在 C++ 中出现了一个问题,你得到了一个指向基类的指针,这个对象实际上是从这个基类继承的,并且你想要复制它。调用复制构造函数不会调用继承类的复制构造函数,而是实际调用基类的复制构造函数。

Observe:

观察:

class Base {

public:
   Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};

class Derived : public Base {

public:
   Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}

Base * obj = new Derived;
Base * obj2 = new Derived(*obj);

The code above would produce the output:

上面的代码将产生输出:

"Base copy constructor"

This is clearly not the behaviour the programmer wanted! The programmer was attempting to copy an object of type "Derived" but instead got back an object of type "Base"!!

这显然不是程序员想要的行为!程序员试图复制“派生”类型的对象,但取回了“基础”类型的对象!!

The issue is rectified by using the aforementioned idiom. Observe the example written above, re-written to use this idiom:

该问题已通过使用上述习语得到纠正。观察上面写的例子,重新编写以使用这个习语:

class Base {

public:
  virtual Base * clone () const = 0; //this will need to be implemented by derived class

protected:
   Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};

class Derived : public Base {

public:
  virtual Base * clone () const {

    //call private copy constructor of class "Derived"
    return static_cast<Base *>( new Derived(*this) );
  }

//private copy constructor:
private:
   Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}

Base * obj = new Derived;
Base * obj2 = obj->clone();

The code above would produce the output:

上面的代码将产生输出:

"Base copy constructor"
"Derived copy constructor"

In other words, the object that was constructed in of desired type "Derived", and not of the type "Base"!

换句话说,以所需类型“Derived”而不是“Base”类型构造的对象!

As you can see, in the Derived type, the copy constructor was intentionally made private, because it would be bad API design to give programmers to ability to accidentally try to call the copy constructor manually, rather than using the clever interface provided by clone(). Put another way, a directly callable public copy constructor available could cause programmers to make the mistake mentioned in part 1. In this case, best practise would have the copy constructor be hidden from view, and only indirectly accessible by using the method "clone()".

如您所见,在 Derived 类型中,复制构造函数被有意设为私有,因为让程序员意外尝试手动调用复制构造函数的能力是糟糕的 API 设计,而不是使用 clone( 提供的巧妙接口) )。换句话说,一个可直接调用的公共复制构造函数可能会导致程序员犯第 1 部分中提到的错误。在这种情况下,最佳实践是将复制构造函数隐藏在视图之外,并且只能通过使用方法“clone( )”。