Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Copy constructor (C++)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
{{Short description|Constructor that copies the state of another object}} {{Use dmy dates|date=March 2021}} In the [[C++]] [[programming language]], a '''copy constructor''' is a special [[Constructor (computer science)|constructor]] for creating a new [[Object (computer science)|object]] [[Object copy|as a copy]] of an existing object. Copy constructors are the standard way of copying objects in C++, as opposed to [[cloning (programming)|cloning]], and have C++-specific nuances. The first argument of such a constructor is a reference to an object of the same type as is being constructed (const or non-const), which might be followed by parameters of any type (all having default values). Normally the [[compiler]] automatically creates a copy constructor for each [[Class (computer science)|class]] (known as an '''implicit''' copy constructor) but for special cases the [[programmer]] creates the copy constructor, known as a '''user-defined''' copy 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 generally needed when an object owns [[Data pointer|pointers]] or non-shareable [[Reference (computer science)|references]], such as to a [[Computer file|file]], in which case a [[Destructor (computer science)|destructor]] and an [[Assignment operator in C++|assignment operator]] should also be written (see [[Rule of three (C++ programming)|Rule of three]]). == Definition == Copying of objects is achieved by the use of a copy constructor and an [[Assignment operator in C++|assignment operator]]. A copy constructor has as its first parameter a (possibly const or [[Volatile variable|volatile]]) [[Reference (C++)|reference]] to its own class type. It can have more arguments, but the rest must have default values associated with them.<ref>INCITS ISO IEC 14882-2003 12.8.2. ''[http://webstore.ansi.org/ansidocstore/product.asp?sku=INCITS%2FISO%2FIEC+14882%2D2003] {{Webarchive|url=https://web.archive.org/web/20070608060639/http://webstore.ansi.org/ansidocstore/product.asp?sku=INCITS%2FISO%2FIEC+14882%2D2003 |date=8 June 2007 }}''</ref> The following would be valid copy constructors for class <code>X</code>: <syntaxhighlight lang="cpp"> X(const X& copy_from_me); X(X& copy_from_me); X(volatile X& copy_from_me); X(const volatile X& copy_from_me); X(X& copy_from_me, int = 0); X(const X& copy_from_me, double = 1.0, int = 42); ... </syntaxhighlight> The first one should be used unless there is a good reason to use one of the others. One of the differences between the first and the second is that temporaries can be copied with the first. For example: <syntaxhighlight lang="cpp"> X a = X(); // valid given X(const X& copy_from_me) but not valid given X(X& copy_from_me) // because the second wants a non-const X& // to create a, the compiler first 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 not be relied // upon because it's non-standard. </syntaxhighlight> A similar difference applies when directly attempting to copy a <code>const</code> object: <syntaxhighlight lang="cpp"> const X a; X b = a; // valid given X(const X& copy_from_me) but not valid given X(X& copy_from_me) // because the second wants a non-const X& </syntaxhighlight> The <code>X&</code> form of the copy 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 <code>[[std::auto_ptr]]</code>. A reference must be provided: <syntaxhighlight lang="cpp"> X a; X b = a; // valid if any of the copy constructors are defined // since a reference is being passed. </syntaxhighlight> The following are invalid copy constructors because <code>copy_from_me</code> is not passed as reference (<code>&</code>) : <syntaxhighlight lang="cpp"> X(X copy_from_me); X(const X copy_from_me); </syntaxhighlight> because the call to those constructors would require a copy as well, which would result in an infinitely recursive call. The following cases may result in a 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 brace-enclosed initializer list These cases are collectively called ''copy-initialization'' and are equivalent to:<ref name="C++03 8.5/12">[[International Organization for Standardization|ISO]]/[[International Electrotechnical Commission|IEC]] (2003). ''[[ISO/IEC 14882|ISO/IEC 14882:2003(E): Programming Languages - C++]] Β§8.5 Initializers [dcl.init]'' para. 12</ref> <code>T x = a;</code> It is however, not guaranteed that a copy constructor will be called in these cases, because the [[ISO/IEC 14882|C++ Standard]] allows the compiler to optimize the copy away in certain cases, one example being the [[return value optimization]] (sometimes referred to as RVO). == Operation == An object can be assigned value using one of the two techniques: * Explicit assignment in an expression * Initialization === Explicit assignment in an expression === <syntaxhighlight lang="cpp"> Object a; Object b; a = b; // translates as Object::operator=(const Object&), thus a.operator=(b) is called // (invoke simple copy, not copy constructor!) </syntaxhighlight> === Initialization === An object can be initialized by any one of the following ways. a. Through declaration <syntaxhighlight lang="cpp">Object b = a; // translates as Object::Object(const Object&) (invoke copy constructor)</syntaxhighlight> b. Through function arguments <syntaxhighlight lang="cpp">type function(Object a);</syntaxhighlight> c. Through function return value <syntaxhighlight lang="cpp">Object a = function();</syntaxhighlight> The copy constructor is used only for initializations, and does not apply to assignments where the assignment operator is used instead. The implicit copy constructor of a class calls base copy constructors and copies its members by means appropriate to their type. If it is a class type, the copy constructor is called. If it is a scalar type, the built-in assignment operator is used. Finally, if it is an array, each element is copied in the manner appropriate to its type.<ref>INCITS ISO IEC 14882-2003 12.8.8. ''[http://webstore.ansi.org/ansidocstore/product.asp?sku=INCITS%2FISO%2FIEC+14882%2D2003] {{Webarchive|url=https://web.archive.org/web/20070608060639/http://webstore.ansi.org/ansidocstore/product.asp?sku=INCITS%2FISO%2FIEC+14882%2D2003 |date=8 June 2007 }}''</ref> By using a user-defined copy constructor the programmer can define the behavior to be performed when an object is copied. ==Examples== These examples illustrate how copy constructors work and why they are sometimes required. ===Implicit copy constructor=== [[File:UML copy constructor.svg]] Consider the following example: <syntaxhighlight lang="cpp"> #include <iostream> class Person { public: explicit Person(int age) : age(age) {} int age; }; int main() { Person timmy(10); Person sally(15); Person timmy_clone = timmy; std::cout << timmy.age << " " << sally.age << " " << timmy_clone.age << std::endl; timmy.age = 23; std::cout << timmy.age << " " << sally.age << " " << timmy_clone.age << std::endl; } </syntaxhighlight> '''Output''' 10 15 10 23 15 10 As expected, <code>timmy</code> has been copied to the new object, <code>timmy_clone</code>. While <code>timmy</code>'s age was changed, <code>timmy_clone</code>'s age remained the same. This is because they are totally different objects. The compiler has generated a copy constructor for us, and it could be written like this: <syntaxhighlight lang="cpp"> Person(const Person& other) : age(other.age) // Calls the copy constructor of the age. { } </syntaxhighlight> So, when do we really need a user-defined copy constructor? The next section will explore that question. ===User-defined copy constructor=== Consider a very simple [[dynamic array]] class like the following: <syntaxhighlight lang="cpp"> #include <iostream> class Array { public: explicit Array(int size) : size(size), data(new int[size]) {} ~Array() { if (data != nullptr) { delete[] data; } } int size; int* data; }; int main() { Array first(20); first.data[0] = 25; { Array copy = first; std::cout << first.data[0] << " " << copy.data[0] << std::endl; } // (1) first.data[0] = 10; // (2) } </syntaxhighlight> '''Output''' 25 25 Segmentation fault Since we did not specify a copy constructor, the compiler generated one for us. The generated constructor would look something like: <syntaxhighlight lang="cpp"> Array(const Array& other) : size(other.size), data(other.data) {} </syntaxhighlight> The problem with this constructor is that it performs a [[shallow copy]] of the ''data'' pointer. It only copies the address of the original data member; this means they both share a pointer to the same chunk of memory, which is not what we want. When the program reaches line '''(1)''', ''copy's'' destructor gets called (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 ''copy's'' data, because they share the same pointer, it also deleted ''first's'' data. Line '''(2)''' now accesses invalid data and writes to it. This produces a [[segmentation fault]]. If we write our own copy constructor that performs a ''deep copy'' then this problem goes away. <syntaxhighlight lang="cpp"> // for std::copy #include <algorithm> Array(const Array& other) : size(other.size), data(new int[other.size]) { std::copy(other.data, other.data + other.size, data); } </syntaxhighlight> Here, we are creating a new '''int''' array and copying the contents to it. Now, ''other's'' destructor deletes only its data, and not ''first's'' data. Line '''(2)''' will not produce a segmentation fault anymore. Instead of doing a deep copy right away, there are some optimization strategies that can be used. These allow you to safely share the same data between several objects, thus saving space. The [[copy-on-write]] strategy makes a copy of the data only when it is written to. [[Reference counting]] keeps the count of how many objects are referencing the data, and will delete it only when this count reaches zero (e.g. <code>boost::shared_ptr</code>). ==Bitwise copy constructor== There is no such thing as "bitwise copy constructor" in C++. However, the default generated copy constructor copies by invoking copy constructors on members, and for a raw pointer member this will copy the raw pointer (i.e. not a deep copy). ==Logical copy constructor== [[File:Logical Copy Constructor.jpg|thumb|It can be seen that in a logical copy constructor, a new dynamic member variable is created for the pointer along with copying the values.<ref>Computer Science A Structured Approach Using C++ by Behrouz A. Forouzan and Richard F. Gilberg, figure 10-9, page 507</ref>]] A logical copy constructor makes a true copy of the structure as well as its dynamic structures. Logical copy constructors come into the picture mainly when there are pointers or complex objects within the object being copied. ==Explicit copy constructor== An explicit copy constructor is one that is declared explicit by using the '''explicit''' keyword. For example: <syntaxhighlight lang="cpp"> explicit X(const X& copy_from_me); </syntaxhighlight> It is used to prevent copying of objects at function calls or with the copy-initialization syntax. ==See also== * [[Assignment operator in C++]] * [[Object copying]] * [[Rule of three (C++ programming)]] == References == {{Reflist}} {{C++ programming language}} [[Category:C++]] [[Category:Method (computer programming)]] [[Category:Articles with example C++ code]]
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)
Pages transcluded onto the current version of this page
(
help
)
:
Template:C++ programming language
(
edit
)
Template:Reflist
(
edit
)
Template:Short description
(
edit
)
Template:Use dmy dates
(
edit
)
Template:Webarchive
(
edit
)