You must pass to std::make_shared
the parameters that you'd pass to your type's constructor, and they are forwarded.
You can then convert the resulting pointer to a base pointer implicitly.
std::shared_ptr<Type> p = std::make_shared<DerivedType>(...);
Let's dig a bit in the "why" in your question.
std::shared_ptr<Type>(new DerivedType);
This does work, and does nothing noteworthy. However, std::make_shared
is usually preferred, because the latter can allocate std::shared_ptr
's bookkeeping data along with your object, and thus is faster and cheaper, as well as exception-safe*.
std::make_shared<Type>(DerivedType(...))
You saw it : it doesn't work. What happens here is that you create a DerivedType
instance. std::make_shared
happily forwards it to the constructor of Type
.
Overload resolution happens, and Type
's copy constructor (or its move constructor, if available) is called, with a reference to your DerivedType
's base part. And a plain Type
object gets instantiated and pointed to. The original DerivedType
vanishes. This issue as a whole is called slicing.
* Note on exception safety : Shoud you use a function of the form :
void func(std::shared_ptr<A> a, std::shared_ptr<B> b);
... constructing the std::shared_ptr
s like so :
func(std::shared_ptr<A>(new A), std::shared_ptr<B>(new B);
... can leak if, for example, new A
is called, then new B
, and the latter throws an exception. The A
has not yet been wrapped into a smart pointer, and is unrecoverable.