banner



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:

  1. When an object is returned by value
  2. When an object is passed (to a function) by value as an argument
  3. When an object is thrown
  4. When an object is caught by value
  5. 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]

It can be seen that in a logical copy constructor, a new dynamic fellow member variable is created for the pointer along with copying the values.[four]

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]

  1. ^ INCITS ISO IEC 14882-2003 12.8.2. [i] Archived 8 June 2007 at the Wayback Machine
  2. ^ ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §viii.5 Initializers [dcl.init] para. 12
  3. ^ INCITS ISO IEC 14882-2003 12.8.viii. [2] Archived 8 June 2007 at the Wayback Machine
  4. ^ 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

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel