Reputation: 20746
Why this code can't compile? If i'll change copy constructor access level to public, it'll be ok and print "Foo::Foo(int)". If i'll write "Foo instance(0);" instead of "Foo instance = 0;" it'll also ok. Why? And what's the point of this behavior?
#include <iostream>
struct Foo
{
public:
int i;
Foo(int i) : i(i) { std::cout << "Foo::Foo(int) \n"; }
private:
Foo(const Foo&) { std::cout << "Foo::Foo(const Foo&) \n"; }
};
int main()
{
Foo instance = 0;
}
Upvotes: 0
Views: 74
Reputation: 110658
Foo instance = 0;
uses copy initialization. The 0
is converted to a Foo
object using the non-explicit constructor Foo(int i)
which is then copied to make instance
. It is equivalent to:
Foo instance = Foo(0);
This requires the copy constructor which you have made private.
When you make it public, the reason the conversion constructor prints but the copy constructor does not is because the copy can be elided by the compiler for optimization. It's the one form of optimization that may change the execution of your code. The copy constructor still needs to be public, however, regardless of whether it is elided or not. In other words, the copy needs to be possible before it can be elided.
If you make the conversion constructor explicit
, it won't compile:
explicit Foo(int i) : i(i) { std::cout << "Foo::Foo(int) \n"; }
Upvotes: 2
Reputation: 258618
Because
Foo instance = 0;
is copy initialization and requires an accessible copy constructor. It attempts to create a temporary Foo
from 0
, using the conversion constructor, and then create instance
from the temporary Foo
using the copy constructor.
By contrast,
Foo instance(0);
is direct initialization and only requires the conversion constructor.
Related: What's the motivation behind having copy and direct initialization behave differently?
Upvotes: 1