Constructor initializer list is not calling copy constructor [duplicate]
Asked Answered
B

2

16

So I was learning about constructor initializer list and I wrote the following code :

class Mango
{
  public:

  Mango(){cout<<"Mango::ctor()";}
  Mango(const Mango& other){cout<<"Mango::copy_ctor()";}
};

class Box
{
    public:

    Box() : mango(Mango()) //**doesn't call copy constructor**
    {
    }

    Mango mango;
};

int main()
{
  Box box; 

   return 0;
}

I used g++ compiler for this. Its calling the constructor not copy constructor. It should call copy constructor right because I am creating an object to create another object? What's the issue here and what does standard says about it?

Bacitracin answered 20/6, 2018 at 6:33 Comment(1)
The default constructor is called because you do Mango(). What then happens is copy-elision.Austria
S
18

Because of copy elision, the copy-construction is omitted here. This behavior is guaranteed from C++17. Before C++17 it's not mandatory; the compilers are permitted, but not required to perform copy elision1.

Under the following circumstances, the compilers are required to omit the copy- and move- construction of class objects even if the copy/move constructor and the destructor have observable side-effects. They need not be present or accessible, as the language rules ensure that no copy/move operation takes place, even conceptually:

  • In initialization, if the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object:

      T x = T(T(T())); // only one call to default constructor of T, to initialize x
    

That means, mango will initialized by the default constructor directly.


[1] In fact most implementations would also perform copy elision before C++17. With Gcc you can try with -fno-elide-constructors option in pre-C++17 mode to disable copy elision.

Selfrestraint answered 20/6, 2018 at 6:37 Comment(0)
S
2

As songyuanyao already explained so well in his excellent answer, the compiler is permitted to optimize away the invocation of the copy constructor in a number of cases.

Still, I'd like to address a different part of your question, just in case there is some misunderstanding:

I used g++ compiler for this. Its calling the constructor not copy constructor. It should call copy constructor right because I am creating an object to create another object? What's the issue here and what does standard says about it?

Your copy constructor needs to be provided with a (const Mango& other) in order to be invoked. If the compiler were to not perform copy elision, you would first see a call to the "normal" constructor "Mango::ctor()" followed by a call to the copy-constructor "Mango::copy_ctor()". Copy elision merely optimizes away the unnecessary copy-constructor call - the constructor for the object needs to be called in either way in order to get the Mango() object in Box() : mango(Mango())

Sham answered 20/6, 2018 at 8:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.