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?
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;
}
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!".
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.
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 :)
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.
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()".
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.
Related
I know we can explicitly call the constructor of a class in C++ using scope resolution operator, i.e. className::className(). I was wondering where exactly would I need to make such a call.
You also sometimes explicitly use a constructor to build a temporary. For example, if you have some class with a constructor:
class Foo
{
Foo(char* c, int i);
};
and a function
void Bar(Foo foo);
but you don't have a Foo around, you could do
Bar(Foo("hello", 5));
This is like a cast. Indeed, if you have a constructor that takes only one parameter, the C++ compiler will use that constructor to perform implicit casts.
It is not legal to call a constructor on an already-existing object. That is, you cannot do
Foo foo;
foo.Foo(); // compile error!
no matter what you do. But you can invoke a constructor without allocating memory - that's what placement new is for.
char buffer[sizeof(Foo)]; // a bit of memory
Foo* foo = new(buffer) Foo(); // construct a Foo inside buffer
You give new some memory, and it constructs the object in that spot instead of allocating new memory. This usage is considered evil, and is rare in most types of code, but common in embedded and data structure code.
For example, std::vector::push_back uses this technique to invoke the copy constructor. That way, it only needs to do one copy, instead of creating an empty object and using the assignment operator.
Most often, in a child class constructor that require some parameters :
class BaseClass
{
public:
BaseClass( const std::string& name ) : m_name( name ) { }
const std::string& getName() const { return m_name; }
private:
const std::string m_name;
//...
};
class DerivedClass : public BaseClass
{
public:
DerivedClass( const std::string& name ) : BaseClass( name ) { }
// ...
};
class TestClass :
{
public:
TestClass( int testValue ); //...
};
class UniqueTestClass
: public BaseClass
, public TestClass
{
public:
UniqueTestClass()
: BaseClass( "UniqueTest" )
, TestClass( 42 )
{ }
// ...
};
... for example.
Other than that, I don't see the utility. I only did call the constructor in other code when I was too young to know what I was really doing...
I think the error message for compiler error C2585 gives the best reason why you would need to actually use the scope-resolution operator on the constructor, and it does in with Charlie's answer:
Converting from a class or structure type based on multiple inheritance. If the type inherits the same base class more than once, the conversion function or operator must use scope resolution (::) to specify which of the inherited classes to use in the conversion.
So imagine you have BaseClass, and BaseClassA and BaseClassB both inherit BaseClass, and then DerivedClass inherits both BaseClassA and BaseClassB.
If you are doing a conversion or operator overload to convert DerivedClass to a BaseClassA or BaseClassB, you will need to identify which constructor (I'm thinking something like a copy constructor, IIRC) to use in the conversion.
In general you do not call the constructor directly. The new operator calls it for you or a subclass calls the parent class' constructors. In C++, the base class is guarenteed to be fully constructed before the derived class' constructor starts.
The only time you would call a constructor directly is in the extremely rare case where you are managing memory without using new. And even then, you shouldn't do it. Instead you should use the placement form of operator new.
I don't think you would typically use that for the constructor, at least not in the way you're describing. You would, however, need it if you have two classes in different namespaces. For example, to specify the difference between these two made-up classes, Xml::Element and Chemistry::Element.
Usually, the name of the class is used with the scope resolution operator to call a function on an inherited class's parent. So, if you have a class Dog that inherits from Animal, and both of those classes define the function Eat() differently, there might be a case when you want to use the Animal version of eat on a Dog object called "someDog". My C++ syntax is a little rusty, but I think in that case you would say someDog.Animal::Eat().
There are valid use cases where you want to expose a classes constructors. If you wish to do your own memory management with an arena allocator for example, you'll need a two phase construction consisting of allocation and object initialization.
The approach I take is similar to that of many other languages. I simply put my construction code in well known public methods (Construct(), init(), something like that) and call them directly when needed.
You can create overloads of these methods that match your constructors; your regular constructors just call into them. Put big comments in the code to warn others that you are doing this so they don't add important construction code in the wrong place.
Remember that there is only one destructor method no matter which construction overload was used, so make your destructors robust to uninitialized members.
I recommend against trying to write initializers that can re-initialize. It's hard to tell the case where you are looking at an object that just has garbage in it because of uninitialized memory vs. actually holding real data.
The most difficult issue comes with classes that have virtual methods. In this case the compiler normally plugs in the vtable function table pointer as a hidden field at the start of the class. You can manually initialize this pointer, but you are basically depending on compiler specific behavior and it's likely to get your colleagues looking at you funny.
Placement new is broken in many respects; in the construction/destruction of arrays is one case so I tend not to use it.
Consider the following program.
template<class T>
double GetAverage(T tArray[], int nElements)
{
T tSum = T(); // tSum = 0
for (int nIndex = 0; nIndex < nElements; ++nIndex)
{
tSum += tArray[nIndex];
}
// Whatever type of T is, convert to double
return double(tSum) / nElements;
}
This will call a default constructor explicitly to initialize the variable.
This question already has answers here:
What is a non-trivial constructor in C++?
(3 answers)
Closed 8 years ago.
In C++, if a copy constructor is not defined the compiler will do that for you. If one is defined, compiler would not. The compiler generated copy constructor can be trivial or non-trivial. In a trivial copy constructor it does a member-wise copy. That's it.
However, if there is a virtual function, the copy constructor is non-trivial. It cannot just to bit-wise copy.
So here is my program. There is nothing special. Just to make my point..
#include<iostream>
using namespace std;
class baseClass
{
public:
int var;
int* varPtr;
const float floatVar;
int &intRefVar;
baseClass(int value) : var(value), varPtr(&var), floatVar(value), intRefVar(var)
{
cout << "baseClass constructor" << endl;
}
baseClass(const baseClass& objToCopy) : var(objToCopy.var), varPtr(&var), floatVar(objToCopy.floatVar), intRefVar(var)
{
cout << "baseClass copy constructor" << endl;
}
virtual void func()
{
cout << "Just a virtual func." << endl;
}
};
class derivedClass : public baseClass
{
public:
derivedClass(int value) : baseClass(value)
{
cout << "derivedClass constructor" << endl;
}
derivedClass(const derivedClass& objToCopy) : baseClass(objToCopy)
{
cout << "derivedClass copy constructor" << endl;
}
virtual void func()
{
cout << "Just another virtual func." << endl;
}
};
int main(int argc, char** argv)
{
derivedClass derClassObj1(10);
derivedClass derClassObj2(derClassObj1);
return 0;
}
In this program,
I have defined a copy constructor
I have a virtual function so the copy constructor is non-trivial
Here are my questions:
How does a non-trivial copy constructor differ from a trivial one due to the presence of a vptr?
Why cannot the vptr be copied? If both objects of same type (same level in the inheritance), they both can point to the same vtable, can they not?
Since I have defined my own copy constructor, does the compiler 'add' special instructions to my copy constructor to handle the virtualness?
Cheers.
How does a non-trivial copy constructor differ from a trivial one due to the presence of a vptr?
The vptr is not copied from the source object, but has to be initialized to point to the virtual table of the destination class. Therefore, a straight "memcpy" copy from source to destination is not possible.
Also, keep in mind that having a vptr is not strictly a requirement, a compliant implementation could implement virtual dispatching some other way (I don't know what that would be though). Although, AFAIK, all implementations use this mechanism. But whichever way an implementation chooses to do things, it is clear that there will be some piece of information like a vptr that will have to be set in some way that is incompatible with a straight "memcpy" copy.
Why cannot the vptr be copied? If both objects of same type (same level in the inheritance), they both can point to the same vtable, can they not?
The sticky issue here is that assumption you made that "both objects of same type". This is not true in the general case. The source object could very well be of some other derived class and therefore have a different virtual table pointer. Another (more rare) practical issue has to do with cross-modular code (in different DLL/so files or executables), where two objects of the same type might use different virtual tables (e.g., there are some corner cases or hackish code in which this is possible without breaking ODR, like different template instantiations).
But the point is that there is no way that the compiler can be assured that for any use of the copy-constructor it is safe to just copy the vptr from the source object and expect it to be appropriate for the destination object.
Since I have defined my own copy constructor, does the compiler 'add' special instructions to my copy constructor to handle the virtualness?
Yes. It does. I don't remember the exact specification, but basically the requirement is that by the time you hit the body of the constructor, the vptr (or whatever other mechanism used for dynamic dispatch) is initialized. That essentially requires the compiler to add code to implicitly initialize the vptr, in all user-defined constructors.
I think the single most important obstacle is slicing. The copy constructor accepts a const reference to the object to be copied and that reference might be bound to a derived class. If there are no virtual bases, no vptr and no non-trivially copyable data members, the copy constructor could be implemented as
Foo(const Foo& o) noexcept
{
std::memcpy(this, &o, sizeof(Foo));
}
because even if the argument is bound to an object that is derived from Foo, its first sizeof(Foo) bytes will be a complete Foo object with any additional members coming after that. However, if there is a vptr – possibly as the very first member – it must be implemented like so
Foo(const Foo& o) noexcept
{
std::memcpy(this, &o, sizeof(Foo));
this->__vptr = Foo::__vptr;
}
Regarding your question
Since I have defined my own copy constructor, does the compiler “add” special instructions to my copy constructor to handle the virtualness?
This is not special to the copy constructor. Before any constructor's body will be entered, the implementation will have made sure that all base objects and any non-trivial data mebers will be constructed. So if you write a copy-constructor, it will already see a semi-constructed *this object with (in case of a type with virtual function members) the vptr set to the type of the currently constructed class. The last part is emphasized because the vptr will change during construction from base to most derived as the various constructors are called.
std::unique_ptr has a deleted copy constructor, which means that if you have a unique_ptr in your class Foo as a data member then you must write your own copy constructor for Foo and manually deep-copy that member (even if the compiler-generated copy constructor would be fine for all other members).
In order to be able to copy in a polymorphic way, the clone() method pattern can be used. Let's assume our objects have a clone method like this:
class Base {
virtual std::unique_ptr<Base> clone() = 0;
};
Foo looks like this now:
class Foo {
public:
...
Foo(Foo const& other)
: b(other.b->clone())
, // init 10 more members that could otherwise be auto-copied just fine
// with the automatically generated copy constructor
{}
...
private:
std::unique_ptr<Base> b;
//10 more data members
};
Now, I found a way to auto-clone Foo::b, by writing a wrapper over unique_ptr that defines the copy constructor and assignment by calling clone.
template <typename T>
class auto_cloned_unique_ptr
{
private:
std::unique_ptr<T> up;
public:
// copy constructor
auto_cloned_unique_ptr(auto_cloned_unique_ptr<T> const& other)
: up(other.up->clone()) {}
// copy assignment
auto_cloned_unique_ptr<T>& operator =(auto_cloned_unique_ptr<T> const& other)
{
this->up = other.up->clone();
return *this;
}
auto_cloned_unique_ptr(std::unique_ptr<T> _up)
: up(std::move(_up)) {}
// Delegate everything else to unique_ptr
auto_cloned_unique_ptr(auto_cloned_unique_ptr<T>&& other)
: up(std::move(other.up)) {}
auto_cloned_unique_ptr<T>& operator =(auto_cloned_unique_ptr<T>&& other)
{
this->up = std::move(other.up);
return *this;
}
auto operator *() const {return *up;}
auto operator->() const {return up.operator->();}
auto get() -> const {return up.get();}
};
Now if we use this we don't need to define our own copy constructor:
class Foo2 {
public:
...
private:
auto_cloned_unique_ptr<Base> b;
//10 more data members
};
Is such an approach very much frowned upon (for using a non-standard wrapper over unique_ptr)?
Let me first paraphrase what you want to do: You want that each instance of Foo has its own instance of Base in b; in particular, if you copy a Foo, the copy will have its own new Base, initially with the same "value". In other words, Base should behave like a value.
At the same time, you can't store Base directly in Foo because it is an abstract class. In other words, you want b to be polymorphic.
There you have it: you want a polymorphic value. Other people have recognized this need and proposed for C++20 as polymorphic_value<Base>. From the documentation:
The class template, polymorphic_value, confers value-like semantics on
a free-store allocated object. A polymorphic_value may hold an
object of a class publicly derived from T, and copying the
polymorphic_value will copy the object of the derived type.
It has a reference implementation that you can use as of now. Very simply put, it is an wrapper around std::unique_ptr similar to what you propose.
The problem with your approach is that it is changing the meaning of a unique_ptr. The key thing about a unique_ptr is that it tells who is the owner of an object. If you add a copy constructor for unique_ptr, what does that mean? Are you copying the ownership? A and B both uniquely own the thing? That does not make sense. If they share ownership, then you should be using the shared_ptr to indicate the shared ownership. If you want to have a unique owner of a copy of the object, you would naturally indicate that by make_unique(*pFoo). With base and derived objects, having the base object have a
virtual unique_ptr<Foo> Clone() const=0;
is a perfectly normal construct. That is, the derived classes know how to copy themselves so they don't produce a sliced copy, but they return a unique_ptr to the base class to indicate that you will own the copy they have produced. Within these clone operations, yes, you will need to explicitly handle non-copyable members of the derived classes, so you won't be able to just use a default or generated copy constructor. You need to answer "what does it mean to copy something that contains this thing that can't be copied?"
As a concrete example, what would it mean to copy a derived class that had a mutex? What if it were locked and another thread were waiting on it? See why it's hard to give a general answer?
This approach is fine, but you should be very carefull not to clone your objects when you did not intentd to.
Also inherriting from unique_ptr might improve performance
Observation: The constructor of ClassMain needs to call Init before it can constructor a member variable a. Since the ClassA has no default constructor, the code doesn't compile.
ClassA
{
public:
// This class has no default constructor
ClassA(...){}
};
class ClassMain
{
public:
ClassMain(...) {
Init(...);
a = ClassA(...); // error: ClassA has no default constructor
// a has to been constructed after the Init is called!
}
ClassMain(...) {
Init(...);
call other functions
a = ClassA(...);
}
private:
// initialize environment
void Init(...) {}
private:
ClassA a;
};
Question> The simple solution is to provide a default constructor for ClassA. However, I would like to know whether there is a better solution to address the issue above?
The better solution is not to require an Init function at all. You're trying to reinvent constructors, and breaking their design in the process.
If Init does too much work for a constructor, then do it outside and pass the resulting resources into ClassMain as a constructor argument; notice how you're already doing all the work in the constructor's scope anyway, thereby not gaining anything appreciable over proper initialisation.
Of course, if you must perform a ton of work before initialising a, and you cannot pass in a ClassA& from the outside and initialise from that, then you're simply going to have to have a be an indirect member.
There is one nasty workaround you could use: have Init actually be a base constructor...
The obvious solution is to call Init() from the initializer list of an early member or a base class. Once this subobject is constructed its results can be passed to the constructors of other subobjects. For example, when defining stream classes I typically privately inherit from a virtual base containing the stream buffer:
struct somebuf_base {
somebuf sbuf;
// ...
};
class somestream
: private virtual somebuf_base
, public std::ostream
{
public:
somestream(someargs)
: somebuf_base(someargs)
, std::ostream(&this->sbuf) {
}
// ...
};
Since base classes are constructed in the order they appear but virtual bases before non-virtual bases, the base class containing the sbuf member is constructed first. Its constructor replaces your Init() function.
When using C++ as of the 2011 revision, you might also use forwarding constructors to share logic between multiple constructors.
It's easier to take a pointer to ClassA; So, you can instantiate it whenever you want.(after the init())
If you used a pointer, don't forget to implement the virtual destructor and release the allocated memory for the ClassA *a
If you absolutely must call some function at the start of your constructor, and can't put that setup into some base class or early-constructed member, you could use this ugly trick:
ClassMain::ClassMain(int main_param)
: a( (Init(init_arg), class_a_arg1), class_a_arg2 )
{
}
In this case: No, we cannot avoid that.
The reason is that when calling Init or any other member function you are guaranteed by the language that the object you are in exists. As a is a member of ClassMain it must be constructed before any function in ClassMain can be called.
The only chance that you have here is to refactor the code.
As the QObject documentation and many others explain, a QObject has an identity and thus hides its copy constructor and assignment operator.
However, I'm not deriving from QObject for its dynamic properties feature or the signals/slots feature. I only want reflection, or the ability to access Foo::staticMetaObject.
class Foo : public QObject {
Q_OBJECT
Q_ENUMS(Color)
public:
enum Color { Blue, Red, Pink };
private:
Color color;
};
Q_DECLARE_METATYPE(Foo::Color)
I then can't copy Foo with:
Foo a;
Foo b;
a = b;
What's the best way to allow copy and assignment in this case? Do I absolutely need to write a copy constructor and assignment operator? What would they look like? Will reflection still work?
If you are only interested in having reflection for
the class name,
enums and flags (Q_ENUMS, Q_FLAGS),
class info (Q_CLASSINFO),
you can use Q_GADGET instead of Q_OBJECT:
class Foo {
Q_GADGET
Q_ENUMS(Color)
public:
enum Color { Blue, Red, Pink };
private:
Color color;
};
which will declare and define Foo::staticMetaObject.
You can certainly implement both a copy constructor and a copy assignment operator in your derived class, but it's likely a sign of bad design. Take this example:
#include <iostream>
class Base {
public:
Base() {}
private:
Base(const Base& other) {
std::cout << "Base copy constructor invoked!" << std::endl;
}
};
class Derived : public Base {
public:
Derived() {}
Derived(const Derived& other) {
std::cout << "Derived copy constructor invoked!" << std::endl;
}
};
int main(int argc, char** argv) {
Derived a;
Derived b = a;
return 0;
}
This will compile just fine. However, as expected, when you run the resulting program, all that is printed is Derived copy constructor invoked!. When the base class declares its copy constructor/copy assignment operator as private, that doesn't prevent derived classes from implementing their own versions. It simply prevents derived classes from calling the base class versions.
And therein lies the problem: it's always good practice to make sure you copy all parts of an object, so that you indeed have two distinct copies. Part of your object includes the data owned by the base class, so you should always make sure to invoke the base class's copy constructor/copy assignment operator to ensure that a full copy is made. But that data is by design non-copyable. Thus, it is impossible to copy all parts of the object.
It's up to you if you want to stick with this design. One important thing to ask yourself is, does your derived class really need to be copyable at all? If not, then there's nothing to worry about!
I don't know much about qt, but if the copy constructor is not allowed then there should be a reason for it (which is discussed in the link you posted). You can change your design not to have it.
Still if you insist then memcpy can be your last resort. I don't recommend it personally, because you have to take care about deep copying, vtable etc. which are not always trivial.