Search

9.12 — Copy initialization

Consider the following line of code:

This statement uses copy initialization to initialize newly created integer variable x to the value of 5.

However, classes are a little more complicated, since they use constructors for initialization. This lesson will examine topics related to copy initialization for classes.

Copy initialization for classes

Given our Fraction class:

Consider the following:

If you were to compile and run this, you’d see that it produces the expected output:

6/1

This form of copy initialization is evaluated the same way as the following:

And as you learned in the previous lesson, this can potentially make calls to both Fraction(int, int) and the Fraction copy constructor (which may be elided for performance reasons). However, because eliding isn’t guaranteed, it’s better to avoid copy initialization for classes, and use direct or uniform initialization instead.

Rule: Avoid using copy initialization, and use uniform initialization instead.

Other places copy initialization is used

There are a few other places copy initialization is used, but two of them are worth mentioning explicitly. When you pass or return a class by value, that process uses copy initialization.

Consider:

In the above program, function makeNegative takes a Fraction by value and also returns a Fraction by value. When we run this program, we get:

Copy constructor called
Copy constructor called
-5/3

The first copy constructor call happens when fiveThirds passed as an argument into makeNegative() parameter f. The second call happens when the return value from makeNegative() is passed back to main().

In the above case, both the argument passed by value and the return value can not be elided. However, in other cases, if the argument or return value meet specific criteria, the compiler may opt to elide the copy constructor. For example:

In this case, the compiler will probably elide the copy constructor, even though variable s is returned by value.

9.13 -- Converting constructors, explicit, and delete
Index
9.11 -- The copy constructor

17 comments to 9.12 — Copy initialization

  • KnowMore

    "In the above case, both the argument passed by value and the return value can not be elided. However, in other cases, if the argument or return value meet specific criteria, the compiler may opt to elide the copy constructor."
    What is the specific criteria that has to be met?

  • Omri

    Thank you for the answer.
    So, a ref var can bind to an l-value, meaning memory locations that hold l-values and can be reached by memory address.
    A const ref var can bind to these memory locations and also to "temporary locations" where, for example, anonymous values are stored for a duration dictated by the context of their creation (for whatever this means)…
    When a const ref var binds to such a temporary and non addressable value (perhaps living in a register?), is there a copy of this value being created elsewhwere so it can be further referenced by the const ref var during its lifetime or otherwise…? Thank you again.

  • Omri

    In: frac class I defined, in addition to a default constructor, a copy constructor as follows leaving out the const qualifier:
    frac(frac &f) :m_num(f.m_num), m_denom(f.m_denom)
    {std::cout << "Copy constructor called\n";}
    as opposed to:
    frac(const frac &f) :m_num(f.m_num), m_denom(f.m_denom)
    {std::cout << "Copy constructor called\n";}
    In main:
    frac f1(1,2); compiled. Following it: frac f2(f1); compiled. Following it frac f3(frac(3,6)); did not compile.

    The compiler complained:
    cannot bind non-const lvalue reference of type ‘frac&’ to an rvalue of type ‘frac’ frac f3(frac(3,6));

    When I add the const qualifier into the copy constructor definition all goes well.
    As I understand this message, It seems that: frac(3,6) does not bind to: frac &f but does bind to: const frac &f.
    I understand that anonymous frac(3,6) is an rvalue.
    Being anonymous It perhaps cannot be referenced later since its existance in memory is only upon its creation and immediate usage (what ever this means)…
    How does the const qualifier solve this?

    • Alex

      Non-const references can only bind to l-values. Const references can bind to l-values and r-values. Your anonymous frac is an r-value, so it can only be bound to a const reference.

  • susenj

    Pardon my ignorance, but I still didn’t get why the second call of copy constructor would be made in the last example of negative fractions.

    • Alex

      The lesson explains it here:

      > The first copy constructor call happens when fiveThirds passed as an argument into makeNegative() parameter f. The second call happens when the return value from makeNegative() is passed back to main().

      Essentially, we get a call to the copy constructor whenever we have a class variable passed by value. That happens twice in this example: once passing fiveThirds to the function, and once when the return value is passed back.

  • Vijay

    Hi Alex, why in this program compiler elide the copy constructor?

  • Nazime

    In the first exemple in the main  you forgot the " () " juste after the main
    Consider the following:

    Whene i copied that i get an error and i didn’t notice that at the first place x)
    i Like this website *_*

  • Andrew Terry

    If you were to compile and run this, you’d see that it produces the expected output:

    6

    No it is 6/1

  • Nyap

    This is whats really getting me confused

    However, because eliding isn’t guaranteed, it’s better to avoid copy initialization for classes, and use direct or uniform initialization instead.

    But isn’t that the same for all forms of initialization? that eliding is not guaranteed? or is the compiler just less likely to elide if its in copy init form?

    • Alex

      There’s no need to elide direct or uniform initialization because they are already as efficient as possible (there’s no extraneous objects created).

  • anand

    This form of copy initialization is evaluated the same way as the following:

    ;
    is it not supposed to be:

    ;

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter