c++ – Why is the copy constructor not called?

Question:

I have this code

#include <iostream>

using namespace std;

class Unit{
    int a_;
    char* pch_;
    public:
    Unit(){ cout << "Simple constr" << endl;}
    Unit(int r) : a_(r), pch_(new char[100]){ cout << "Constr " << endl;}
    Unit(const Unit& ){ cout << "Constr copy " << endl;}
    ~Unit(){
        delete [] pch_;
        cout << "Destr" << endl;
    }
};

int main(){
    Unit a = 20;
    return 0;
}

Only the constructor with the parameter is called, and of course the destructor.

Why not: 1. The constructor is called with the parameter: Unit(20). 2. There is an assignment to an object that has not been created – this is copying. The copy constructor is called. Just rvalue can be passed by const T&. 3. Destructor for rvalue. 4. Destructor for a.

Answer:

In "classic" C++ (C++98), your copy-initialization is

Unit a = 20;

really conceptually meant precisely

Unit a = Unit(20);

using the conversion constructor Unit::Unit(int) and then the copy constructor Unit::Unit(const Unit &) . However, even in the "classic" C ++ compiler was allowed to exclude the formation of an intermediate temporary object and optimize the code to direct initialization (direct-initialization)

Unit a(20);

those. avoid calling a copy constructor even if the copy constructor had side effects. This optimization is called copy elision . (Even with copy elision, an accessible copy constructor was still required.)

Since C++17, the language has a guaranteed copy elision, in which your initialization is guaranteed to be treated as

Unit a(20);

without requiring a copy constructor.

Those. in any case, you should not (and should never) expect a mandatory call to the copy constructor here. In "classic" C++, the copy constructor could be called here, but nothing more.


In your particular case, copy-initialization behaves identically to direct-initialization, but in general, significant differences between these forms of initialization remain in C++17. for instance

struct A {
  A(int) {}
};

struct B {
  operator int() const { return 0; }
};

int main()
{
  B b;
  A a1(b);  // Все в порядке
  A a2 = b; // Ошибка
}

PS There is no "assignment" here, of course, at all.

Scroll to Top