Consider this example constructing shared_ptr<T>
in various ways and returning:
#include <memory>
#include <iostream>
class Base
{
public:
virtual ~Base() {}
Base(int y) : y_(y) {}
int y_;
};
class Derived : public Base
{
public:
Derived(int y, int z) : Base(y), z_(z) {}
int z_;
};
std::shared_ptr<Base> A()
{
return std::shared_ptr<Base>(new Derived(1, 2));
}
std::shared_ptr<Base> B()
{
std::shared_ptr<Derived> result = std::make_shared<Derived>(Derived(1, 2));
return result;
}
std::shared_ptr<Base> C()
{
std::shared_ptr<Base> result = std::make_shared<Base>(Derived(1, 2));
return result;
}
std::shared_ptr<Base> D()
{
return std::make_shared<Base>(Derived(1, 2));
}
int main(int argc, char** argv)
{
// Works fine...
std::shared_ptr<Derived> resultA = std::dynamic_pointer_cast<Derived>(A());
// Works fine...
std::shared_ptr<Derived> resultB = std::dynamic_pointer_cast<Derived>(B());
// Does not cast to base? ...
std::shared_ptr<Derived> resultC = std::dynamic_pointer_cast<Derived>(C());
// Object returns fine (of type Base), but cannot be cast to Derived?
std::shared_ptr<Base> resultCBase = C();
std::shared_ptr<Derived> resultCDerived = std::dynamic_pointer_cast<Derived>(resultCBase);
// Does not cast to derived...
std::shared_ptr<Derived> resultD = std::dynamic_pointer_cast<Derived>(D());
return 0;
}
In summary:
Returning std::make_shared<T>
seems to work fine and allows caller to correctly cast. (see A()
).
Using make_shared<Derived>
to create a Derived, and then relying on implicit casting to return a shared_ptr<Base>
works and allows caller to correctly cast. (see B()
).
However for C()
and D()
when using make_shared<Base>(Derived(...))
, shared_ptr<Base>
is constructed (seems correct) but cannot cast to std::shared_ptr<Derived>
?
I'm not familiar with what make_shared<T>
gives (Although other answers of SO allude to better type safety and single allocation?), however it doesn't seem to perform or behave in the same manner as when replacing with std::shared_ptr<T>(new T(...))
?
Could someone please explain to me what is happening here and why it does not work as I expect (I presume I am using it wrong, or there is some subtle behaviour trait that I should know when using it)?
Since the above example has discrepancies, A()
& B()
working, but not C()
and D()
(assuming I am using it correctly)... why is make_shared<T>
recommended over std::shared_ptr<T>(new T(...))
, and are there any exceptions which would mean it is not recommended over the other?