#include <iostream>
using namespace std;
class Y {
public:
Y(int ) {
cout << "Y(int)\n";
}
Y(const Y&) {
cout << " Y(const Y&)\n";
}
};
int main() {
Y obj1 = 2; // Line 1
}
Output: Y(int)
Expected Output: Y(int) Y(const Y&)
Question> Based on my understanding, Line 1 will first create a temporary object Y(2), and then assign the temporary object to obj1
. Thus, I expect both Y(int)
and Y(const Y&)
are called. But the output from vs2010 only reports the first one(i.e. Y(int)
). Why?
Why?
Because under certain conditions (specified by paragraph 12.8/31 of the C++11 Standard) calls to the copy constructor or move constructor can be elided even though those special functions (or the destructor) have side effects:
This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):
— [...]
— when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move
— [...]
This is the only exception to the so-called "as-if" rule, which normally constrains the kind of transformations (optimizations) that a compiler can perform on a program in order to preserve its observable behavior.
Notice, that the above mechanism is called copy elision - even when it's actually a call to the move constructor that is being elided.
This is because the constructor has only one parameter and it's not marked explicit
, so the compiler automatically turns:
Y obj1 = 2;
Into:
Y obj1(2);
To prevent this behaviour, use:
explicit Y(int ) {
cout << "Y(int)\n";
}
(and compilation will fail in your case).
This is called copy initialization
. Y(int )
is a conversion constructor. that is
single-parameter constructor that is declared without the function specifier explicit
the compiler is allowed to elide the extra copy and use your conversion constructor
. Which means
Y obj1 = 2; // Line 1
is equivalent to
Y obj1(2); // Line 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With