Topics Covered
In this section, we will have a look at more C++ constructors. The following will be covered:
- Copy Constructor
- Copy Assignment Operators
- Move Constructor
Copy Constructor
Definition
General Definition
A non-template constructor for class X is a copy constructor if its first parameter is of type X&
, const X&
, volatile X&
or const volatile X&
, and either there are no other parameters or else all other parameters have default arguments.
Example:
class X {
public:
X ( const X& ); X ( const X&, int = 1 ); };
Here the copy constructor is public
. This class is call Copy Constructible.
Saying this what happens in the following case?
class X {
public:
X ( X& x, int i );
X ( ) { };
};
X::X ( X& x, int i = 0) {
}
We will discuss more of these cases when we dive deeper in another article.
Like normal constructors, these can also be deleted, or default.
X ( const X& ) = default; X ( const X& ) = delete;
Now the question is; do we always need to pass a reference in copy constructor?
Well let's see the case below:
class X {
public:
X ( const X v);
};
X a;
X b = a;
Now what will happen? Here X b = a;
the code will look like b( X v = a)
. Now this is again a copy constructor call. This will happen like this recursively until we are out of stack space and the program will crash. So this is not allowed. This will throw up error telling this is illegal copy constructor.
A class can have multiple copy constructors, e.g.:
class X {
public:
X ( const X& );
X ( X& );
};
A member function template is never instantiated to produce a copy constructor signature. Like:
class X {
public:
template<typename T>
X ( T );
X ( );
};
X a;
void foo ( ) {
X b ( a ); }
In this case, the implicitly declared copy constructor is used.
The reason being follows:
- The template can be instantiated to mimic a copy constructor but as per the standard statement it is not a copy constructor (If you haven’t seen the definition see again, it explicitly tells as non-templated). So this means the class doesn’t define one.
- The compiler now generates a copy-constructor in the right circumstance. So say the compiler also instantiates this templated code. Then when the time to choose comes, the over loading resolution chooses the non templated function rather than the templated one as it does for other functions.
Implicitly-declared Copy Constructor
If no user-defined copy constructors are provided for a class type, the compiler will always declare a copy constructor with the following type:
class X {
public:
inline X ( const X& ); };
The const
modifier is applied only if the following conditions are met:
- All direct and virtual bases of “X” have copy constructors with references to
const
or to const volatile
as their first parameters. - All non-static members of “X” have copy constructors with references to
const
or to const volatile
as their first parameters.
Some Facts
- The implicitly-defined copy constructor for a non-union class
X
performs a member-wise copy of its bases and members. - The order of initialization is the same as the order of initialization of bases and members in a user-defined constructor.
- The implicitly-defined copy constructor for a union
X
copies the object representation of X
.
Deleted implicitly-declared copy constructor
The implicitly-declared or defaulted copy constructor for class X is defined as deleted or in simpler pre C++11 terms undefined (the compiler cannot define them) if the following conditions are met:
X
has non-static data members that cannot be copied (have deleted, inaccessible, or ambiguous copy constructors) X
has direct or virtual base class that cannot be copied (has deleted, inaccessible, or ambiguous copy constructors) X
has direct or virtual base class with a deleted or inaccessible destructor.
Trivial copy constructor
A trivial copy constructor is a constructor that creates a byte-wise copy of the object representation of the argument and performs no other action. Objects with trivial copy constructors can be copied by copying their object representations manually e.g. with std::memmove
. All data types compatible with the C language (POD types) are trivially copyable.
The copy constructor for class X
is trivial if all of the following is true:
- It is not user-provided (that is, it is implicitly-defined or defaulted), and if it is defaulted, its signature is the same as implicitly-defined
X
has no virtual member functions X
has no virtual base classes - The copy constructor selected for every direct base of
X
is trivial - The copy constructor selected for every non-static class type (or array of class type) member of
X
is trivial
Implicitly-defined copy constructor
If the implicitly-declared copy constructor is neither deleted nor trivial, it is defined (that is, a function body is generated and compiled) by the compiler.
- For union types, the implicitly-defined copy constructor copies the object representation (as by
std::memmove
). - For non-union class types (
class
and struct
), the constructor performs full member-wise copy of the object’s bases and non-static members in their initialization order using direct initialization.
Usage
class X {
public:
X ( const X& ); };
X a;
X b = a;
X b ( a );
void f ( const X v ); f ( a );
void f ( ) {
X a;
return a;
}
If a class X only has a copy constructor with a parameter of type X&
, an initializer of type const X
or volatile X
cannot initialize an object of type (possibly cv-qualified) X
.
class X {
public:
X ( ) ; X ( X& ) ; };
const X a;
X b = a;
Copy Assignment Operator
Definition
A user-declared copy assignment operator X::operator=
is a non-static non-template member function of class X
with exactly one parameter of type X, X&
, const X&
, volatile X&
or const volatile X&
. As with any function and constructor, they can be default or deleted.
class X {
public:
X& operator=( X );
X& operator=( const X& );
X& operator=( const X& ) = default;
X& operator=( const X& ) = delete;
};