How To Create A Copy Constructor For A Template
In the C++ programming language, a copy constructor is a special constructor for creating a new object as a copy of an existing object. Copy constructors are the standard mode of copying objects in C++, as opposed to cloning, and have C++-specific nuances.
The starting time argument of such a constructor is a reference to an object of the aforementioned type every bit is being synthetic (const or not-const), which might exist followed by parameters of any type (all having default values).
Normally the compiler automatically creates a copy constructor for each class (known equally an implicit copy constructor) but for special cases the programmer creates the copy constructor, known as a user-defined re-create constructor. In such cases, the compiler does not create one. Hence, there is always one copy constructor that is either defined by the user or by the system.
A user-defined copy constructor is by and large needed when an object owns pointers or non-shareable references, such as to a file, in which instance a destructor and an assignment operator should also be written (see Rule of three).
Definition [edit]
Copying of objects is achieved by the apply of a copy constructor and an assignment operator. A copy constructor has as its first parameter a (maybe const or volatile) reference to its own class type. It can have more than arguments, simply the rest must take default values associated with them.[1] The following would be valid copy constructors for class 10
:
X ( const X & copy_from_me ); Ten ( 10 & copy_from_me ); 10 ( volatile 10 & copy_from_me ); X ( const volatile Ten & copy_from_me ); 10 ( X & copy_from_me , int = 0 ); 10 ( const X & copy_from_me , double = one.0 , int = 42 ); ...
The offset i should exist used unless at that place is a good reason to apply ane of the others. One of the differences betwixt the first and the 2d is that temporaries tin can exist copied with the first. For case:
X a = Ten (); // valid given X(const X& copy_from_me) simply not valid given 10(X& copy_from_me) // because the second wants a non-const X& // to create a, the compiler beginning creates a temporary by invoking the default constructor // of X, then uses the copy constructor to initialize as a copy of that temporary. // Temporary objects created during program execution are always of const type. So, const keyword is required. // For some compilers both versions actually work but this behaviour should non be relied // upon because it's non-standard.
A similar difference applies when directly attempting to re-create a const
object:
const X a ; X b = a ; // valid given X(const X& copy_from_me) but non valid given Ten(X& copy_from_me) // considering the second wants a not-const X&
The X&
form of the re-create constructor is used when it is necessary to modify the copied object. This is very rare but it can be seen used in the standard library's std::auto_ptr
. A reference must be provided:
X a ; X b = a ; // valid if any of the copy constructors are defined // since a reference is existence passed.
The post-obit are invalid re-create constructors considering copy_from_me
is not passed every bit reference (&
) :
X ( 10 copy_from_me ); X ( const X copy_from_me );
because the telephone call to those constructors would require a copy equally well, which would issue in an infinitely recursive phone call.
The following cases may result in a phone call to a copy constructor:
- When an object is returned by value
- When an object is passed (to a function) by value as an argument
- When an object is thrown
- When an object is caught by value
- When an object is placed in a caryatid-enclosed initializer list
These cases are collectively called copy-initialization and are equivalent to:[two] T x = a;
It is however, not guaranteed that a re-create constructor will be chosen in these cases, because the C++ Standard allows the compiler to optimize the copy away in certain cases, 1 example being the return value optimization (sometimes referred to as RVO).
Performance [edit]
An object tin be assigned value using one of the ii techniques:
- Explicit assignment in an expression
- Initialization
Explicit assignment in an expression [edit]
Object a ; Object b ; a = b ; // translates as Object::operator=(const Object&), thus a.operator=(b) is called // (invoke simple re-create, non re-create constructor!)
Initialization [edit]
An object can be initialized past whatever 1 of the post-obit ways.
a. Through annunciation
Object b = a ; // translates as Object::Object(const Object&) (invoke copy constructor)
b. Through function arguments
c. Through function return value
The copy constructor is used only for initializations, and does not utilize to assignments where the assignment operator is used instead.
The implicit re-create constructor of a class calls base re-create constructors and copies its members by ways appropriate to their blazon. If it is a class blazon, the copy constructor is called. If it is a scalar type, the built-in assignment operator is used. Finally, if it is an assortment, each chemical element is copied in the manner appropriate to its type.[3]
By using a user-defined copy constructor the programmer tin can ascertain the beliefs to be performed when an object is copied.
Examples [edit]
These examples illustrate how copy constructors piece of work and why they are sometimes required.
Implicit re-create constructor [edit]
Consider the following instance:
#include <iostream> class Person { public : explicit Person ( int age ) : age ( age ) {} int age ; }; int main () { Person timmy ( 10 ); Person emerge ( 15 ); Person timmy_clone = timmy ; std :: cout << timmy . historic period << " " << sally . age << " " << timmy_clone . age << std :: endl ; timmy . age = 23 ; std :: cout << timmy . age << " " << sally . age << " " << timmy_clone . historic period << std :: endl ; }
Output
x 15 10 23 15 10
As expected, timmy
has been copied to the new object, timmy_clone
. While timmy
's historic period was changed, timmy_clone
's age remained the same. This is because they are totally different objects.
The compiler has generated a copy constructor for the states, and information technology could be written similar this:
Person ( const Person & other ) : age ( other . age ) // Calls the copy constructor of the age. { }
And so, when practise we really demand a user-divers copy constructor? The next department will explore that question.
User-divers copy constructor [edit]
Consider a very uncomplicated dynamic array class like the following:
#include <iostream> grade Assortment { public : explicit Array ( int size ) : size ( size ), data ( new int [ size ]) {} ~ Array () { if ( data != nullptr ) { delete [] data ; } } int size ; int * data ; }; int principal () { Assortment first ( 20 ); first . data [ 0 ] = 25 ; { Array copy = kickoff ; std :: cout << starting time . data [ 0 ] << " " << copy . information [ 0 ] << std :: endl ; } // (one) first . data [ 0 ] = 10 ; // (2) }
Output
25 25 Partitioning fault
Since nosotros did non specify a copy constructor, the compiler generated one for united states of america. The generated constructor would look something like:
Array ( const Assortment & other ) : size ( other . size ), information ( other . data ) {}
The trouble with this constructor is that it performs a shallow copy of the information pointer. It simply copies the accost of the original data member; this ways they both share a pointer to the same chunk of memory, which is not what we want. When the plan reaches line (i), re-create'due south destructor gets chosen (because objects on the stack are destroyed automatically when their scope ends). Array's destructor deletes the data array of the original, therefore, when it deleted re-create's information, considering they share the same pointer, information technology also deleted starting time's data. Line (ii) now accesses invalid data and writes to it. This produces a segmentation fault.
If we write our own copy constructor that performs a deep re-create and then this problem goes abroad.
// for std::copy #include <algorithm> Array ( const Array & other ) : size ( other . size ), information ( new int [ other . size ]) { std :: copy ( other . data , other . data + other . size , data ); }
Here, nosotros are creating a new int array and copying the contents to it. Now, other's destructor deletes just its data, and non kickoff'due south data. Line (2) will non produce a segmentation fault anymore.
Instead of doing a deep copy right away, in that location are some optimization strategies that can be used. These allow you to safely share the same data betwixt several objects, thus saving space. The copy-on-write strategy makes a re-create of the information only when it is written to. Reference counting keeps the count of how many objects are referencing the information, and will delete it only when this count reaches zero (e.grand. boost::shared_ptr
).
Re-create constructors and templates [edit]
Contrary to expectations, a template copy constructor is not a user-defined re-create constructor. Thus it is not enough to only have:
template < typename A > Array :: Array ( A const & other ) : size ( other . size ()), data ( new int [ other . size ()]) { std :: copy ( other . begin (), other . stop (), data ); }
(Note that the type of A
tin can be Array
.) A user-divers, non-template copy constructor must also be provided for construction of Array from Array.
Bitwise copy constructor [edit]
There is no such affair as "bitwise copy constructor" in C++. However, the default generated copy constructor copies by invoking re-create constructors on members, and for a raw pointer member this will copy the raw pointer (i.e. non a deep copy).
Logical copy constructor [edit]
A logical copy constructor makes a true copy of the structure as well as its dynamic structures. Logical copy constructors come into the pic mainly when there are pointers or complex objects within the object being copied.
Explicit copy constructor [edit]
An explicit re-create constructor is one that is declared explicit by using the explicit keyword. For example:
explicit X ( const X & copy_from_me );
It is used to prevent copying of objects at role calls or with the copy-initialization syntax.
See too [edit]
- Assignment operator in C++
- Object copying
References [edit]
- ^ INCITS ISO IEC 14882-2003 12.8.2. [i] Archived 8 June 2007 at the Wayback Machine
- ^ ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §viii.5 Initializers [dcl.init] para. 12
- ^ INCITS ISO IEC 14882-2003 12.8.viii. [2] Archived 8 June 2007 at the Wayback Machine
- ^ Computer science A Structured Arroyo Using C++ by Behrouz A. Forouzan and Richard F. Gilberg, figure x-ix, folio 507
How To Create A Copy Constructor For A Template,
Source: https://en.wikipedia.org/wiki/Copy_constructor_%28C++%29
Posted by: jamesinaboust.blogspot.com
0 Response to "How To Create A Copy Constructor For A Template"
Post a Comment