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.
Related
List C.67 in the cpp core guideline says: A base class should suppress copying, and provide a virtual clone instead if "copying" is desired.
If the copy constructor is defined as deleted in the base, then the move operations are also suppressed for base class and all derived classes.
On the other hand, move operations may improve performance. My question is what would be realistic approach we should adopt when we design a class hierarchy?
Suppose we have the following class hierarchy? how should we design A and B to properly support copy and move operations.
class A{
public:
A(const std::string& as) = deleted;
//should we define other copy/move operators?
virtual void foo();//
virtual ~A();//
private:
std::string s;
};
class B: public A{
public:
//how do we define copy/move operators?
void foo() override;
~B() override;
private:
std::vector<std::string> vs;
};
Confusions
Copy vs. clone
First, note that clone is not “copy for objects of polymorphic type”: they are simply different operations with different semantics.
Copy (via a copy constructor) means “create an object of statically specified type with the value of another”. (Recall that constructors cannot be virtual, for want of a current object whose class could provide the behavior.) The user must specify the type, and should expect that the copied object is “reinterpreted” (sliced) as the known, specified type if it is in fact of a derived type.
clone copies an object of a dynamically known derived class as another object of that class. Since the argument determines the type of the result, the user cannot specify it and indeed does not (statically) know what is chosen. (Heap allocation is a corollary.)
Which one you want depends on what lifetime and type you want the result to have (including “the same type as that one” as a choice). I find it puzzling that someone would write a copy (e.g., a by-value parameter whose specified type is a concrete base class) and be surprised by what they had chosen.
Virtual assignment
Next, note that an abstract class need not fear slicing except on assignment (which must be via a reference). Assignment can be virtual (since an object already exists), but it can’t statically avoid slicing because the types need not match:
struct B {
virtual ~B()=default;
virtual B& operator=(const B&)=default;
// ...
};
struct D1 : B {
D& operator=(const B&) override;
// ...
};
struct D2 : B {/* ... */};
void f() {
B &&b=D1();
b=D2(); // ok
}
The assignment must use just the common B part, or… throw? If the assignment can fail, it’d be clearer to provide it as a function: perhaps bool assign_like(const B&) &; that returns false if the types differ.
Protection
So we indeed must do something about at least assignment if we want to avoid the risk of slicing. The Core Guidelines idea of deleting the assignment operator is reasonable, but I would just make it protected in each abstract base class.
Concrete leaves only
If you never inherit from a concrete class, that’s all you need to prevent slicing: the implicit (public) special member functions in the leaf classes do not slice, automatically use the base’s corresponding SMFs, and can in turn be used automatically as appropriate. (For example, the concrete classes may then be passed by value.)
“Deep” hierarchy
In a concrete base class, you have two choices for each SMF:
Make it protected anyway, denying the possibility of deliberately copying an object (even if the source’s complete object type is known statically).
Leave it available and send any confused users of the class hierarchy here to learn about the difference between copy and clone (and the impossibility of a “fully virtual” assignment).
According to the C++ standard, a class that has virtual functions cannot have a trivial copy constructor:
A copy/move constructor for class X is trivial if it is not user-provided and if
— class X has no virtual functions (10.3) and no virtual base classes (10.1), and
— the constructor selected to copy/move each direct base class subobject is trivial, and
— for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;
otherwise the copy/move constructor is non-trivial.
Now, imagine a class hierarchy that satisfies all the mentioned conditions except the 'no virtual functions' condition:
struct I
{
virtual void f() = 0;
};
struct D final : I
{
void f() override
{
}
};
From an implementation's point of view those classes contain only a pointer to the virtual dispatch table. And the base class does not have any user-declared constructors, and the derived class is final, so the mentioned pointer can always have a constant value. Given all that, the copy constructor can be trivial, yet the standard explicitly forbids treating it as such.
On the other hand, the conditions of treating such classes as trivially destructible are met. The class does not declare a virtual destructor and uses implicitly-defined destructors.
Requiring triviality of destructors looks like mandating an optimization - implicitly defined destructors should not restore pointers to the virtual table in this case.
But such an optimization goes half-way in my opinion; classes with virtual functions still cannot be memcopied, even if they can be trivially destructed.
The questions:
Are there any reasons I did not think of from an implementation perspective why such classes should have non-trivial copy-constructors?
Are there any reasons the restrictions on triviality for copy-constructors cannot be relaxed in the standard?
Are there any reasons I did not think of from implementation perspective why such classes should have non-trivial copy-constructors?
There is quite obvious one: copy-constructor of I is not trivial. And it is not final, so there can be other derived classes. So it must be non-trivial and set virtual table pointer properly after memcpy, as there could be derived classes relying on it.
Are there any reasons the restrictions on triviality for copy-constructors cannot be relaxed in the standard?
1) Constructor triviality part was simply not revised with inclusion of final keyword.
2) People think that keywords like delete, final and overrride should help avoid most common errors, and clarify programmer intention, not change behavior of the program.
3) It complicates language:
A constructor is trivial, unless you have virtual function, then it is nontrivial, unless your class is final, then it is trivial again, unless something else, then it is not, unless...
4) Nobody though that it is worth writing formal paper for, proving usefulness of this addition to Committee and pushing this change into language.
The copies and moves of polymorphic classes cannot be trivial because it would break slicing copies and moves which copy a base type of an object's dynamic type. For example:
struct Base { virtual int f() { return 0; } };
struct D1 : Base { int f() override { return 1; } };
struct D2 : Base { int f() override { return 2; } };
int main() {
D1 d1;
D2 d2;
Base b = d1; // if this copy constructor were trivial, b would have D1's vtable
b.f(); // ...and this call would return 1 instead of 0.
b = d2; // Ditto: b would have D2's vtable
b.f(); // ...and this call would return 2 instead of 0.
}
Trivial constructors means that no additional effort is needed. So for copy c-tor/assigment operator it means simple memcpy. Virtual functions as you mentioned are creating vtable, which is table of pointers to functions. So if you'd try to copy memory of D object, you'll also copy its vtable. New object would have vtable with pointers pointing to old memory. This would crearly not an ideal situation.
I can understand defaulted constructors, since user defined constructors will disable the compiler generated ones making the object non trivially copyable etc.
In the destructor case, apart from changing access category, what use is there to define a defaulted destructor considering that no user defined member function can disable them (you can't overload destructors anyway) ?
// Which version should I choose ?
struct Example
{
//1. ~Example() = default;
//2. ~Example() {}
//3.
};
Even in the case of virtual destructors, defaulting them would not make them trivial so what good is it doing it?
The exception for trivial destructors omission has to do with the derived class' destructor, not the base one. So virtual ~Foo() = default; is a useful construct to keep the default destructor, but virtualize it.
One use is making the destructor protected or private while potentially keeping the class trivial: just list it after the desired access specifier.
Another: when writing classes, some programmers like to order the class's functions: e.g. constructors, then the destructor, then the non-const "mutating" members, then the const "accessor" members, then static functions. By being able to explicitly = default the destructor, you can list it in the expected order and the reader looking there knows there can't be another misplaced version of it. In large classes, that may have some documentary/safety value.
It also gives you something concrete around which to add comments, which can help some documentation tools realise the comments relate to destruction.
Basically it is about communicating the intent, but pretty redundant.
But in case you're using std::unique_ptr as a member of class you'll need to declare destructor (but only declare) in header. Then you can make it use default implementation in source file like so:
MyClass:~MyClass() = default;
Considering your options I would use first or third one.
As mentioned by Nikos Athanasiou in a comment, a default constructor makes the type trivially destructible, where a user defined one does not. A little code sample will show it:
#include <iostream>
#include <type_traits>
struct A { ~A() = default; };
struct B { ~B() {} };
struct C { ~C() noexcept {} };
int main() {
std::cout
<< std::is_trivially_destructible<A>::value
<< std::is_trivially_destructible<B>::value
<< std::is_trivially_destructible<C>::value
<< std::endl;
return 0;
}
Displays
100
As for virtual destructors, consistency with non-virtual ones and Quentin's answer are appropriate reasons. My personal advice is that you should always use the default when you can, as this is a way to stick to the most canonic behavior.
I'm reading Effective C++, and there is the "Item 9: Never call virtual functions during construction or destruction". And I'm wondering if my code is fine even if it breaks this rule:
using namespace std;
class A{
public:
A(bool doLog){
if(doLog)
log();
}
virtual void log(){
cout << "logging A\n";
}
};
class B: public A{
public:
B(bool doLog) : A(false){
if(doLog)
log();
}
virtual void log(){
cout << "logging B\n";
}
};
int main() {
A a(true);
B b(true);
}
Is there something wrong with this approach? May I get in trouble when I do something more complicated?
It seams to me that most answers didn't get what I did there, and they simply explained again why is calling virtual function from constructor potentially dangerous.
I would like to stress out that output of my program looks like this:
logging A
logging B
So I get A logged when it is constructed and B logged when it is constructed. And that is what I want! But I'm asking if You find anything wrong(potentially dangerous) with my "hack" to overcome the problem with calling virtual function in constructor.
Is there something wrong with this approach?
Answer from Bjarne Stroustrup:
Can I call a virtual function from a constructor?
Yes, but be careful. It may not do what you expect. In a constructor,
the virtual call mechanism is disabled because overriding from derived
classes hasn't yet happened. Objects are constructed from the base up,
"base before derived". Consider:
#include<string>
#include<iostream>
using namespace std;
class B {
public:
B(const string& ss) { cout << "B constructor\n"; f(ss); }
virtual void f(const string&) { cout << "B::f\n";}
};
class D : public B {
public:
D(const string & ss) :B(ss) { cout << "D constructor\n";}
void f(const string& ss) { cout << "D::f\n"; s = ss; }
private:
string s;
};
int main()
{
D d("Hello");
}
the program compiles and produce
B constructor
B::f
D constructor
Note not D::f. Consider what would happen if the rule were different so that D::f() was called from B::B(): Because the constructor D::D() hadn't yet been run, D::f() would try to assign its argument to an uninitialized string s. The result would most likely be an immediate crash.
Destruction is done "derived class before base class", so virtual functions behave as in constructors: Only the local definitions are used - and no calls are made to overriding functions to avoid touching the (now destroyed) derived class part of the object.
For more details see D&E 13.2.4.2 or TC++PL3 15.4.3.
It has been suggested that this rule is an implementation artifact. It is not so. In fact, it would be noticeably easier to implement the unsafe rule of calling virtual functions from constructors exactly as from other functions. However, that would imply that no virtual function could be written to rely on invariants established by base classes. That would be a terrible mess.
And I'm wondering if mine code is fine even if it breaks this rule:
It depends on what you mean by "fine". Your program is well-formed, and its behavior is well-defined, so it won't invoke undefined behavior and stuff like that.
However, one may expect, when seeing a call to a virtual function, that the call is resolved by invoking the implementation provided by the most derived type which overrides that function.
Except that during construction, the corresponding sub-object has not been constructed yet, so the most derived subobject is the one currently being constructed. Result: the call is dispatched as if the function were not virtual.
This is counter-intuitive, and your program should not rely on this behavior. Therefore, as a literate programmer, you should get used to avoid such a pattern and follow Scott Meyer's guideline.
It's "fine" in the sense of being well-defined. It may not be "fine" in the sense of doing what you expect.
You will call the override from the class currently being constructed (or destroyed), not the final override; since the final derived class has not yet been constructed (or has already been destroyed) and so can't be accessed. So you may get in trouble if you wanted the final override to be called here.
Since this behaviour is potentially confusing, it's best to avoid having to do it. I would recommend adding behaviour to a class by aggregation rather than subclassing in that situation; the class members are constructed before the constructor body, and last until after the destructor, and so are available in both those places.
One thing you mustn't do is call a virtual function from the constructor or destructor if it's pure virtual in that class; that's undefined behaviour.
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.