Consider the following code:
#include<iostream>
using namespace std;
class A{
public:
A()=default;
A(int a){cout<<"A(int) called"<<endl;}
A(const A&a);
~A(){cout<<"~A() called"<<endl;}
};
A::A(const A&a){
cout<<"A(const A&) called"<<endl;
}
int main(){
A a = 1;
}
When I use g++8.1 to compile with -fno-elide-constructors
to cancel the RVO, the output was:
A(int) called
A(const A&) called
~A() called
~A() called
I know that this is something called the converting constructor, an implicit conversion from the types of its arguments to the type of its class.
It seems that firstly a temporary object is constructed by A(int)
, secondly the a
object is constructed by the copy-constructor A(const A&)
.
But when I modify my code:
#include<iostream>
using namespace std;
class A{
public:
A()=default;
A(int a){cout<<"A(int) called"<<endl;}
explicit A(const A&a); //use explicit
~A(){cout<<"~A() called"<<endl;}
};
A::A(const A&a){
cout<<"A(const A&) called"<<endl;
}
int main(){
//A a = A(1); //error:no constructor match
A b = 1; //ok
}
It confused me that the b
object is copy-constructed explicitly?! Even if I use the copy initialization?
When I delete the copy-constructor by A(const A&a)=delete;
, it will not work as expected.
However, it is different when I use VS2017. the implicit conversion A a = 1;
has nothing to do with the copy-constructor. Even if I delete the c-c, it works as usual.
The effect of copy initialization here is,
(emphasis mine)
Note that the ojbect is direct-initialized from the converted
A
(fromint
), the copy constructor is marked asexplicit
or not doesn't matter here.BTW: Since C++17 because of mandatory copy elision, the copy-construction will be elided completely.