From the cppreference page on copy-initialization:
Copy-initialization is less permissive than direct-initialization: explicit
constructors are not converting constructors and are not considered for copy-initialization.
So the answer to your first question is "by design". Copy-initialization only considers implicit conversions.
As to why you'd want to disable implicit conversion: it is used as a safety measure when constructing the object might be dangerous, and should therefore be explicit (visible in the code).
For example, let's imagine that std::unique_ptr<T>
's constructor from T*
be implicit. Now let's look at some (contrived) user code:
void forbulate(Foo * const myFoo) {
myFoo->doStuff();
lookAt(myFoo); // My Foo is amazing
myFoo->doMoreStuff();
}
This looks fine at first sight. But what you don't know, is that lookAt
actually has the following prototype:
void lookAt(std::unique_ptr<Foo> yourFoo);
So we are, in fact, silently constructing a unique_ptr<Foo>
to pass to lookAt
. this means something very important: this unique_ptr
is now the owner of myFoo
, and will kill it upon destruction. What actually happens is:
void forbulate(Foo * const myFoo) {
myFoo->doStuff(); // Fine
lookAt(myFoo) // Still fine
; // myFoo is `delete`d !
myFoo->doMoreStuff(); // Ouch, undefined behaviour from accessing a dead object
} // Sorry caller, I accidentally your Foo :(
Note that the deletion itself might be UB already (for example if myFoo
is the address of an automatic instance). In any case, this innocuous-looking code is actually a landmine. Not spreading landmines everywhere is why we have explicit
constructors: with the actual unique_ptr
specification, the code doesn't even compile, and you know what's wrong.