I'm putting a class in my app under std::shared_ptr
, converting existing code. My understanding is that shared_ptr
's constructor from a raw pointer is explicit (e.g., http://www.cplusplus.com/reference/memory/shared_ptr/shared_ptr/), and that makes a great deal of sense to me. However, I'm seeing a weird thing in my app where the constructor seems to me to be acting as if it is implicit. I don't understand how this possible.
First of all, I have a typedef
for my shared_ptr
type:
typedef std::shared_ptr<EidosPropertySignature const> EidosPropertySignature_CSP;
Then I have some code where I construct a new object and add it to a vector of shared pointers:
std::vector<EidosPropertySignature_CSP> properties;
properties.emplace_back(new EidosPropertySignature(...constructor parameters...));
This compiles without even a warning. I don't see how – the result of new EidosPropertySignature
is an EidosPropertySignature *
, which should not be implicitly convertible to the EidosPropertySignature_CSP
that the vector holds, right? I would very much like this construct to produce a compile error, as I thought that it would. Why doesn't it, and is there a way for me to modify my approach so that it does?
There is no implicit conversion here. emplace_back
forwards its arguments directly to the constructor of the element type to construct the new element [sequence.reqmts]:
Appends an object of type
T
constructed withstd::forward<Args>(args)...
.
Thus, emplace_back
is essentially a direct constructor call. push_back
, on the other hand, won't work because that would actually require a conversion…
On a purely conceptional level, implicit conversions are about allowing a value of some type to be converted to a value of a different type if necessary, possibly as part of a longer conversion sequence. Conversions are about building bridges. With an implicit conversion, you tell the compiler: here's a bridge from A
to B
, you may use it to get around. With an explicit conversion, you say: here's a bridge from A
to B
, use it only if I explicitly told you to go to B
; in particular, don't use it if you just want to make your way to somewhere else over B
. When you write emplace_back
, you explicitly say "construct an element". emplace_back
explicitly expresses that an object of the element type be created. You explicitly told the compiler to go to B
. There is nothing implicit about emplace_back
…