Why would you want to separate these two things?
Use case 1
struct Bar {}; struct Foo { Bar bar; }; class OwnsBar { private: const std::shared_ptr<Bar> m_bar; public: OwnsBar(const std::shared_ptr<Bar>& bar) : m_bar(bar) { } }; std::shared_ptr<OwnsBar> CreateBarOwner() { auto foo = std::make_shared<Foo>(); std::shared_ptr<Bar> aliasBarPtr(foo, &foo->bar); return std::make_shared<OwnsBar>(aliasBarPtr); }
Here, aliasBarPtr owns the entire Foo struct and keeps it alive, but it points to the Bar member. This means that (a) aliasBarPtr can be used anywhere a shared_ptr<Bar> is expected, and (b) aliasBarPtr will keep the entire parent Foo alive even after the local foo variable goes out of scope.
Use case 2
void f(const std::shared_ptr<Bar>& bar); void g(Bar& bar) { // don't actually do this unless you have no choice; see comments below std::shared_ptr<Bar> fakeSharedPtrBar(std::shared_ptr<Bar>(), &bar); f(fakeSharedPtrBar); }
fakeSharedPtrBar owns nothing, but it points to bar. In effect, it is a raw pointer masquerading as a shared_ptr.
Note that pulling this little sleight of hand is dangerous; if f passes the fake shared_ptr to someone else who hangs onto it beyond the point that g's Bar is destroyed, things will blow up. Only use this hack if you're absolutely sure f won't do this and refactoring it to take a raw pointer or reference isn't an option.
Use case 3
// Utility function to relocate an object into a shared_ptr using its move constructor // obj will no longer be valid upon returning template<typename T> std::shared_ptr<T> MoveIntoSharedPtr(T& obj) { return std::make_shared<T>(std::move(obj)); } std::shared_ptr<Document> CreateDocument() { auto doc = std::make_shared<Document>(); auto observer1 = std::make_shared<Observer1>(); doc->AddWeakObserver(std::weak_ptr<IDocumentObserver>(observer1)); auto observer2 = std::make_shared<Observer2>(); doc->AddWeakObserver(std::weak_ptr<IDocumentObserver>(observer2)); auto keepAliveTuple = std::make_tuple(doc, observer1, observer2); return std::shared_ptr<Document>(MoveIntoSharedPtr(keepAliveTuple), doc.get()); }
In a previous post, I used a custom deleter to achieve this same thing. That works almost all the time, but you can get odd bugs if the type in question (Document, in the example above) implements enable_shared_from_this. See this stackoverflow question for details.