Search code examples
c++shared-ptr

Why is my shared_ptr able to construct implicitly from a raw pointer?


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?


Solution

  • 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 with std​::​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