48

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?

  • There is no such thing as an assignment constructor, do you mean move constructor? – Praetorian Jul 25 '11 at 01:40
  • it was a typo... corrected it now... assignment operator –  Jul 25 '11 at 02:23
  • he main reason i asked that question is I've been reading c++ books and learning C++ all by myself... and the books I'm reading Lippman,Lajoie c++ Primer and Stroustrup and others do not give enough of real world examples where such an approach would be required. of course, it is not possible to provide an exhaustive list... but a few cases where such an approach would be useful can be illustrated (like the car example by @tc) and i have already stated that there is no pointer or an association with the unique object like a file....... –  Jul 25 '11 at 02:30
  • If you haven't discovered it already, the book "Effective C++" by Scott Meyers is excellent - essential reading for anyone wanting to improve their skills in C++ (a language which provides ample rope to hang yourself... and those all around you). Should be covered in Item 4 (from a quick Google, I don't have my copy to hand). – Luke Usherwood Jun 18 '15 at 02:22
  • You can use [boost::noncopyable](http://www.boost.org/doc/libs/master/libs/core/doc/html/core/noncopyable.html) to save a bunch of boilerplate. As in: `class X : private boost::noncopyable { ... }` – Luke Usherwood Jun 18 '15 at 02:39

7 Answers7

43

One use case is the singleton pattern where 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.

// 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;
}
Eric Z
  • 14,327
  • 7
  • 45
  • 69
  • 2
    ohk... that is one case.... even the constructor would be private in this case.... –  Jul 25 '11 at 02:32
  • With C++11, can we replace the private copy constructor and copy assignment operator with the `=delete`d version (public) to see the same results? – FCo Jul 14 '22 at 16:07
35

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.

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_ptr style 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!".

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • when declaring the copy c'tor as private, will you still need to follow the rule of three? means, would you still need an assignment operator and destructor? – ThunderWiring Dec 08 '16 at 12:47
  • @ThunderWiring: in short, removing the assignment operator is usually a good idea, but the destructor's still needed by any instances that are allowed to be created. For assignment, there are some edge cases where it won't matter - like singletons where self-assignment (which is the only possible assignment) is safe - but that's rarely useful so it's probably still worth snipping the assignment operator to avoid confusion. – Tony Delroy Dec 19 '16 at 23:35
4

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.

tc.
  • 33,468
  • 5
  • 78
  • 96
  • With the problem of vehicle... If we try to expose a car as a vehicle, then there would not be any engine corresponding to that car in that vehicle object.. and so in a sense... you should build a specialized constructor for vehicle that would define taking only the wheels from the car and constructing an object from that... i would say, the problem is the class design rather than the copy constructor thing... –  Jul 25 '11 at 02:41
  • 2
    @Jayesh Badwaik: You were asking for real-world examples. Slightly ugly designs are quite common there, like reality tends to be. Don't even start to look at code that's inspired by specific laws and dozens of years of bureaucracy. There it's even more useful to keep the ugliness local. Forbidding copies can help there: "this class is a bit weird, but it matches Form F11-M3 appendix A" – MSalters Jul 25 '11 at 08:19
4

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 =delete for such purpose. So in C++ 0x making copy ctor private seems to be resrtricted to very exotic cases.

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

user396672
  • 3,106
  • 1
  • 21
  • 31
  • :).. thanks for the info..... i'll look into that... personally.. i felt that the use of copy constructors should be kept to minimum and should certainly be not made pervasive to the full system design (effect should be as limited as possible).... as long as possible... right now I'm dealing with a high performace computational code... so i guess it's okay... but still i feel it would be better without them..... –  Jul 25 '11 at 17:26
1

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • yes i understand... but then that should be left to the programmer right? instead of making it mandatory not to copy the programmer can access the object by reference.... –  Jul 25 '11 at 02:21
  • @Jayesh: A good API is impossible (or very difficult) to misuse. You can still access the object by reference, but that doesn't mean you should be allowed to copy it. – Nicol Bolas Jul 25 '11 at 02:41
1

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.

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"!

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()".

J T
  • 4,946
  • 5
  • 28
  • 38
  • your first example doesn't compile since there are no implicit downcasting in c++ (Base * obj2 = new Derived(*obj) generates an error, *obj can not be implicitly converted to Derived&). So it is unclear, what is a problem you try to solve with virtual constructor idiom – user396672 Jul 25 '11 at 10:13
0

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.

Petar Ivanov
  • 91,536
  • 11
  • 82
  • 95
  • that's my question... exactly why? there can be different reasons... it would be helpful if you could provide some examples... –  Jul 25 '11 at 02:27