Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/memory/shared ptr"

From cppreference.com
< cpp‎ | memory
m (Replaced content with "<table><tbody><tr><td class="mbox-text" style="text-align:center;">Cppreference recommends all new users to use Rust. Please refrain from making No_personal_attacks|pers...")
(Undo revision 158368 by Admin (talk))
Line 1: Line 1:
<table><tbody><tr><td class="mbox-text" style="text-align:center;">Cppreference recommends all new users to use Rust. Please refrain from making [[No_personal_attacks|personal attacks]]
+
{{cpp/title|shared_ptr}}
</td></tr></tbody></table>
+
{{cpp/memory/shared_ptr/navbar}}
<!-- reverting this edit constitutes a personal attack -->
+
{{ddcl|header=memory|since=c++11|1=
 +
template< class T > class shared_ptr;
 +
}}
 +
 
 +
{{tt|std::shared_ptr}} is a smart pointer that retains shared ownership of an object through a pointer. Several {{tt|shared_ptr}} objects may own the same object. The object is destroyed and its memory deallocated when either of the following happens:
 +
* the last remaining {{tt|shared_ptr}} owning the object is destroyed;
 +
* the last remaining {{tt|shared_ptr}} owning the object is assigned another pointer via {{lc|1=operator=}} or {{lc|reset()}}.
 +
 
 +
The object is destroyed using [[cpp/language/delete|delete-expression]] or a custom deleter that is supplied to {{tt|shared_ptr}} during construction.
 +
 
 +
A {{tt|shared_ptr}} can share ownership of an object while storing a pointer to another object. This feature can be used to point to member objects while owning the object they belong to. The stored pointer is the one accessed by {{lc|get()}}, the dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count reaches zero.
 +
 
 +
A {{tt|shared_ptr}} may also own no objects, in which case it is called ''empty'' (an empty {{tt|shared_ptr}} may have a non-null stored pointer if the aliasing constructor was used to create it).
 +
 
 +
All specializations of {{tt|shared_ptr}} meet the requirements of {{named req|CopyConstructible}}, {{named req|CopyAssignable}}, and {{named req|LessThanComparable}} and are [[cpp/language/implicit_cast|contextually convertible]] to {{tt|bool}}.
 +
 
 +
All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of {{tt|shared_ptr}} without additional synchronization even if these instances are copies and share ownership of the same object. If multiple threads of execution access the same instance of {{tt|shared_ptr}} without synchronization and any of those accesses uses a non-const member function of {{tt|shared_ptr}} then a data race will occur; the {{rl|atomic|{{tt|shared_ptr}} overloads of atomic functions}} can be used to prevent the data race.
 +
 
 +
===Member types===
 +
{{dsc begin}}
 +
{{dsc hitem|Member type|Definition}}
 +
{{dsc|{{c|element_type}}|{{rev begin}}
 +
{{rev|until=c++17|{{c|T}}}}
 +
{{rev|since=c++17|{{c|std::remove_extent_t<T>}}}}
 +
{{rev end}}
 +
}}
 +
{{dsc|{{c|weak_type}} {{mark since c++17}}|{{c|std::weak_ptr<T>}}}}
 +
{{dsc end}}
 +
 
 +
===Member functions===
 +
{{dsc begin}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc constructor}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc destructor}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc operator{{=}}}}
 +
 
 +
{{dsc h2|Modifiers}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc reset}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc swap}}
 +
 
 +
{{dsc h2|Observers}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc get}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc operator*}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc operator_at}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc use_count}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc unique}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc operator bool}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc owner_before}}
 +
{{dsc end}}
 +
 
 +
===Non-member functions===
 +
{{dsc begin}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc make_shared}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc allocate_shared}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc pointer_cast}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc get_deleter}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc operator_cmp}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc operator_ltlt}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc swap2}}
 +
{{dsc break}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc atomic}}
 +
{{dsc end}}
 +
 
 +
===Helper classes===
 +
{{dsc begin}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc atomic2}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc hash}}
 +
{{dsc end}}
 +
 
 +
==={{rl|deduction guides|Deduction guides}} {{mark since c++17}}===
 +
 
 +
===Notes===
 +
The ownership of an object can only be shared with another {{tt|shared_ptr}} by copy constructing or copy assigning its value to another {{tt|shared_ptr}}. Constructing a new {{tt|shared_ptr}} using the raw underlying pointer owned by another {{tt|shared_ptr}} leads to undefined behavior.
 +
 
 +
{{tt|std::shared_ptr}} may be used with an [[cpp/language/incomplete type|incomplete type]] {{tt|T}}. However, the constructor from a raw pointer ({{c|template<class Y> shared_ptr(Y*)}}) and the {{c|template<class Y> void reset(Y*)}} member function may only be called with a pointer to a complete type (note that {{lc|std::unique_ptr}} may be constructed from a raw pointer to an incomplete type).
 +
 
 +
The {{tt|T}} in {{c/core|std::shared_ptr<T>}} may be a function type: in this case it manages a pointer to function, rather than an object pointer. This is sometimes used to keep a dynamic library or a plugin loaded as long as any of its functions are referenced:
 +
{{source|
 +
void del(void(*)()) {}
 +
 
 +
void fun() {}
 +
 
 +
int main()
 +
{
 +
    std::shared_ptr<void()> ee(fun, del);
 +
    (*ee)();
 +
}
 +
}}
 +
 
 +
===Implementation notes===
 +
In a typical implementation, {{tt|shared_ptr}} holds only two pointers:
 +
* the stored pointer (one returned by {{lc|get()}});
 +
* a pointer to ''control block''.
 +
 
 +
The control block is a dynamically-allocated object that holds:
 +
* either a pointer to the managed object or the managed object itself;
 +
* the deleter (type-erased);
 +
* the allocator (type-erased);
 +
* the number of {{tt|shared_ptr}}s that own the managed object;
 +
* the number of {{tt|weak_ptr}}s that refer to the managed object.
 +
 
 +
When {{tt|shared_ptr}} is created by calling {{lc|std::make_shared}} or {{lc|std::allocate_shared}}, the memory for both the control block and the managed object is created with a single allocation. The managed object is constructed in-place in a data member of the control block. When {{tt|shared_ptr}} is created via one of the {{tt|shared_ptr}} constructors, the managed object and the control block must be allocated separately.  In this case, the control block stores a pointer to the managed object.
 +
 
 +
The pointer held by the {{tt|shared_ptr}} directly is the one returned by {{lc|get()}}, while the pointer/object held by the control block is the one that will be deleted when the number of shared owners reaches zero.  These pointers are not necessarily equal.
 +
 
 +
The destructor of {{tt|shared_ptr}} decrements the number of shared owners of the control block. If that counter reaches zero, the control block calls the destructor of the managed object. The control block does not deallocate itself until the {{lc|std::weak_ptr}} counter reaches zero as well.
 +
 
 +
In existing implementations, the number of weak pointers is incremented ([https://stackoverflow.com/questions/43297517/stdshared-ptr-internals-weak-count-more-than-expected], [https://www.reddit.com/r/cpp/comments/3eia29/stdshared_ptrs_secret_constructor/ctfeh1p]) if there is a shared pointer to the same control block.
 +
 
 +
To satisfy thread safety requirements, the reference counters are typically incremented using an equivalent of {{lc|std::atomic::fetch_add}} with {{lc|std::memory_order_relaxed}} (decrementing requires stronger ordering to safely destroy the control block).
 +
 
 +
===Example===
 +
{{example
 +
|
 +
|code=
 +
#include <chrono>
 +
#include <iostream>
 +
#include <memory>
 +
#include <mutex>
 +
#include <thread>
 +
 
 +
using namespace std::chrono_literals;
 +
 
 +
struct Base
 +
{
 +
    Base() { std::cout << "Base::Base()\n"; }
 +
 
 +
    // Note: non-virtual destructor is OK here
 +
    ~Base() { std::cout << "Base::~Base()\n"; }
 +
};
 +
 
 +
struct Derived: public Base
 +
{
 +
    Derived() { std::cout << "Derived::Derived()\n"; }
 +
 
 +
    ~Derived() { std::cout << "Derived::~Derived()\n"; }
 +
};
 +
 
 +
void print(auto rem, std::shared_ptr<Base> const& sp)
 +
{
 +
    std::cout << rem << "\n\tget() = " << sp.get()
 +
              << ", use_count() = " << sp.use_count() << '\n';
 +
}
 +
 
 +
void thr(std::shared_ptr<Base> p)
 +
{
 +
    std::this_thread::sleep_for(987ms);
 +
    std::shared_ptr<Base> lp = p; // thread-safe, even though the
 +
                                  // shared use_count is incremented
 +
    {
 +
        static std::mutex io_mutex;
 +
        std::lock_guard<std::mutex> lk(io_mutex);
 +
        print("Local pointer in a thread:", lp);
 +
    }
 +
}
 +
 
 +
int main()
 +
{
 +
    std::shared_ptr<Base> p = std::make_shared<Derived>();
 +
 
 +
    print("Created a shared Derived (as a pointer to Base)", p);
 +
 
 +
    std::thread t1{thr, p}, t2{thr, p}, t3{thr, p};
 +
    p.reset(); // release ownership from main
 +
 
 +
    print("Shared ownership between 3 threads and released ownership from main:", p);
 +
 
 +
    t1.join(); t2.join(); t3.join();
 +
 
 +
    std::cout << "All threads completed, the last one deleted Derived.\n";
 +
}
 +
|p=true
 +
|output=
 +
Base::Base()
 +
Derived::Derived()
 +
Created a shared Derived (as a pointer to Base)
 +
get() = 0x118ac30, use_count() = 1
 +
Shared ownership between 3 threads and released ownership from main:
 +
get() = 0, use_count() = 0
 +
Local pointer in a thread:
 +
get() = 0x118ac30, use_count() = 5
 +
Local pointer in a thread:
 +
get() = 0x118ac30, use_count() = 4
 +
Local pointer in a thread:
 +
get() = 0x118ac30, use_count() = 2
 +
Derived::~Derived()
 +
Base::~Base()
 +
All threads completed, the last one deleted Derived.
 +
}}
 +
 
 +
===Example===
 +
{{example
 +
|
 +
|code=
 +
#include <iostream>
 +
#include <memory>
 +
 
 +
struct MyObj
 +
{
 +
    MyObj() { std::cout << "MyObj constructed\n"; }
 +
 
 +
    ~MyObj() { std::cout << "MyObj destructed\n"; }
 +
};
 +
 
 +
struct Container : std::enable_shared_from_this<Container> // note: public inheritance
 +
{
 +
    std::shared_ptr<MyObj> memberObj;
 +
 
 +
    void CreateMember() { memberObj = std::make_shared<MyObj>(); }
 +
 
 +
    std::shared_ptr<MyObj> GetAsMyObj()
 +
    {
 +
        // Use an alias shared ptr for member
 +
        return std::shared_ptr<MyObj>(shared_from_this(), memberObj.get());
 +
    }
 +
};
 +
 
 +
#define COUT(str) std::cout << '\n' << str << '\n'
 +
 
 +
#define DEMO(...) std::cout << #__VA_ARGS__ << " = " << __VA_ARGS__ << '\n'
 +
 
 +
int main()
 +
{
 +
    COUT( "Creating shared container" );
 +
    std::shared_ptr<Container> cont = std::make_shared<Container>();
 +
    DEMO( cont.use_count() );
 +
    DEMO( cont->memberObj.use_count() );
 +
 
 +
    COUT( "Creating member" );
 +
    cont->CreateMember();
 +
    DEMO( cont.use_count() );
 +
    DEMO( cont->memberObj.use_count() );
 +
 
 +
    COUT( "Creating another shared container" );
 +
    std::shared_ptr<Container> cont2 = cont;
 +
    DEMO( cont.use_count() );
 +
    DEMO( cont->memberObj.use_count() );
 +
    DEMO( cont2.use_count() );
 +
    DEMO( cont2->memberObj.use_count() );
 +
 
 +
    COUT( "GetAsMyObj" );
 +
    std::shared_ptr<MyObj> myobj1 = cont->GetAsMyObj();
 +
    DEMO( myobj1.use_count() );
 +
    DEMO( cont.use_count() );
 +
    DEMO( cont->memberObj.use_count() );
 +
    DEMO( cont2.use_count() );
 +
    DEMO( cont2->memberObj.use_count() );
 +
 
 +
    COUT( "Copying alias obj" );
 +
    std::shared_ptr<MyObj> myobj2 = myobj1;
 +
    DEMO( myobj1.use_count() );
 +
    DEMO( myobj2.use_count() );
 +
    DEMO( cont.use_count() );
 +
    DEMO( cont->memberObj.use_count() );
 +
    DEMO( cont2.use_count() );
 +
    DEMO( cont2->memberObj.use_count() );
 +
 
 +
    COUT( "Resetting cont2" );
 +
    cont2.reset();
 +
    DEMO( myobj1.use_count() );
 +
    DEMO( myobj2.use_count() );
 +
    DEMO( cont.use_count() );
 +
    DEMO( cont->memberObj.use_count() );
 +
 
 +
    COUT( "Resetting myobj2" );
 +
    myobj2.reset();
 +
    DEMO( myobj1.use_count() );
 +
    DEMO( cont.use_count() );
 +
    DEMO( cont->memberObj.use_count() );
 +
 
 +
    COUT( "Resetting cont" );
 +
    cont.reset();
 +
    DEMO( myobj1.use_count() );
 +
    DEMO( cont.use_count() );
 +
}
 +
|output=
 +
 
 +
Creating shared container
 +
cont.use_count() = 1
 +
cont->memberObj.use_count() = 0
 +
 
 +
Creating member
 +
MyObj constructed
 +
cont.use_count() = 1
 +
cont->memberObj.use_count() = 1
 +
 
 +
Creating another shared container
 +
cont.use_count() = 2
 +
cont->memberObj.use_count() = 1
 +
cont2.use_count() = 2
 +
cont2->memberObj.use_count() = 1
 +
 
 +
GetAsMyObj
 +
myobj1.use_count() = 3
 +
cont.use_count() = 3
 +
cont->memberObj.use_count() = 1
 +
cont2.use_count() = 3
 +
cont2->memberObj.use_count() = 1
 +
 
 +
Copying alias obj
 +
myobj1.use_count() = 4
 +
myobj2.use_count() = 4
 +
cont.use_count() = 4
 +
cont->memberObj.use_count() = 1
 +
cont2.use_count() = 4
 +
cont2->memberObj.use_count() = 1
 +
 
 +
Resetting cont2
 +
myobj1.use_count() = 3
 +
myobj2.use_count() = 3
 +
cont.use_count() = 3
 +
cont->memberObj.use_count() = 1
 +
 
 +
Resetting myobj2
 +
myobj1.use_count() = 2
 +
cont.use_count() = 2
 +
cont->memberObj.use_count() = 1
 +
 
 +
Resetting cont
 +
myobj1.use_count() = 1
 +
cont.use_count() = 0
 +
MyObj destructed
 +
}}
 +
 
 +
===See also===
 +
{{dsc begin}}
 +
{{dsc inc|cpp/memory/dsc unique_ptr}}
 +
{{dsc inc|cpp/memory/dsc weak_ptr}}
 +
{{dsc end}}
 +
 
 +
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}

Revision as of 15:19, 8 September 2023

 
 
Utilities library
General utilities
Relational operators (deprecated in C++20)
 
Dynamic memory management
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Allocators
Garbage collection support
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)



 
 
Defined in header <memory>
template< class T > class shared_ptr;
(since C++11)

std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of the following happens:

  • the last remaining shared_ptr owning the object is destroyed;
  • the last remaining shared_ptr owning the object is assigned another pointer via operator= or reset().

The object is destroyed using delete-expression or a custom deleter that is supplied to shared_ptr during construction.

A shared_ptr can share ownership of an object while storing a pointer to another object. This feature can be used to point to member objects while owning the object they belong to. The stored pointer is the one accessed by get(), the dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count reaches zero.

A shared_ptr may also own no objects, in which case it is called empty (an empty shared_ptr may have a non-null stored pointer if the aliasing constructor was used to create it).

All specializations of shared_ptr meet the requirements of CopyConstructible, CopyAssignable, and LessThanComparable and are contextually convertible to bool.

All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object. If multiple threads of execution access the same instance of shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur; the shared_ptr overloads of atomic functions can be used to prevent the data race.

Contents

Member types

Member type Definition
element_type
T (until C++17)
std::remove_extent_t<T> (since C++17)
weak_type (since C++17) std::weak_ptr<T>

Member functions

constructs new shared_ptr
(public member function) [edit]
destructs the owned object if no more shared_ptrs link to it
(public member function) [edit]
assigns the shared_ptr
(public member function) [edit]
Modifiers
replaces the managed object
(public member function) [edit]
swaps the managed objects
(public member function) [edit]
Observers
returns the stored pointer
(public member function) [edit]
dereferences the stored pointer
(public member function) [edit]
provides indexed access to the stored array
(public member function) [edit]
returns the number of shared_ptr objects referring to the same managed object
(public member function) [edit]
(until C++20)
checks whether the managed object is managed only by the current shared_ptr object
(public member function) [edit]
checks if the stored pointer is not null
(public member function) [edit]
provides owner-based ordering of shared pointers
(public member function) [edit]

Non-member functions

creates a shared pointer that manages a new object
(function template) [edit]
creates a shared pointer that manages a new object allocated using an allocator
(function template) [edit]
applies static_cast, dynamic_cast, const_cast, or reinterpret_cast to the stored pointer
(function template) [edit]
returns the deleter of specified type, if owned
(function template) [edit]
(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(C++20)
compares with another shared_ptr or with nullptr
(function template) [edit]
outputs the value of the stored pointer to an output stream
(function template) [edit]
specializes the std::swap algorithm
(function template) [edit]
specializes atomic operations for std::shared_ptr
(function template) [edit]

Helper classes

atomic shared pointer
(class template specialization) [edit]
hash support for std::shared_ptr
(class template specialization) [edit]

Deduction guides (since C++17)

Notes

The ownership of an object can only be shared with another shared_ptr by copy constructing or copy assigning its value to another shared_ptr. Constructing a new shared_ptr using the raw underlying pointer owned by another shared_ptr leads to undefined behavior.

std::shared_ptr may be used with an incomplete type T. However, the constructor from a raw pointer (template<class Y> shared_ptr(Y*)) and the template<class Y> void reset(Y*) member function may only be called with a pointer to a complete type (note that std::unique_ptr may be constructed from a raw pointer to an incomplete type).

The T in std::shared_ptr<T> may be a function type: in this case it manages a pointer to function, rather than an object pointer. This is sometimes used to keep a dynamic library or a plugin loaded as long as any of its functions are referenced:

void del(void(*)()) {}
 
void fun() {}
 
int main()
{
    std::shared_ptr<void()> ee(fun, del);
    (*ee)();
}

Implementation notes

In a typical implementation, shared_ptr holds only two pointers:

  • the stored pointer (one returned by get());
  • a pointer to control block.

The control block is a dynamically-allocated object that holds:

  • either a pointer to the managed object or the managed object itself;
  • the deleter (type-erased);
  • the allocator (type-erased);
  • the number of shared_ptrs that own the managed object;
  • the number of weak_ptrs that refer to the managed object.

When shared_ptr is created by calling std::make_shared or std::allocate_shared, the memory for both the control block and the managed object is created with a single allocation. The managed object is constructed in-place in a data member of the control block. When shared_ptr is created via one of the shared_ptr constructors, the managed object and the control block must be allocated separately. In this case, the control block stores a pointer to the managed object.

The pointer held by the shared_ptr directly is the one returned by get(), while the pointer/object held by the control block is the one that will be deleted when the number of shared owners reaches zero. These pointers are not necessarily equal.

The destructor of shared_ptr decrements the number of shared owners of the control block. If that counter reaches zero, the control block calls the destructor of the managed object. The control block does not deallocate itself until the std::weak_ptr counter reaches zero as well.

In existing implementations, the number of weak pointers is incremented ([1], [2]) if there is a shared pointer to the same control block.

To satisfy thread safety requirements, the reference counters are typically incremented using an equivalent of std::atomic::fetch_add with std::memory_order_relaxed (decrementing requires stronger ordering to safely destroy the control block).

Example

#include <chrono>
#include <iostream>
#include <memory>
#include <mutex>
#include <thread>
 
using namespace std::chrono_literals;
 
struct Base
{
    Base() { std::cout << "Base::Base()\n"; }
 
    // Note: non-virtual destructor is OK here
    ~Base() { std::cout << "Base::~Base()\n"; }
};
 
struct Derived: public Base
{
    Derived() { std::cout << "Derived::Derived()\n"; }
 
    ~Derived() { std::cout << "Derived::~Derived()\n"; }
};
 
void print(auto rem, std::shared_ptr<Base> const& sp)
{
    std::cout << rem << "\n\tget() = " << sp.get()
              << ", use_count() = " << sp.use_count() << '\n';
}
 
void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(987ms);
    std::shared_ptr<Base> lp = p; // thread-safe, even though the
                                  // shared use_count is incremented
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        print("Local pointer in a thread:", lp);
    }
}
 
int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();
 
    print("Created a shared Derived (as a pointer to Base)", p);
 
    std::thread t1{thr, p}, t2{thr, p}, t3{thr, p};
    p.reset(); // release ownership from main
 
    print("Shared ownership between 3 threads and released ownership from main:", p);
 
    t1.join(); t2.join(); t3.join();
 
    std::cout << "All threads completed, the last one deleted Derived.\n";
}

Possible output:

Base::Base()
Derived::Derived()
Created a shared Derived (as a pointer to Base)
	get() = 0x118ac30, use_count() = 1
Shared ownership between 3 threads and released ownership from main:
	get() = 0, use_count() = 0
Local pointer in a thread:
	get() = 0x118ac30, use_count() = 5
Local pointer in a thread:
	get() = 0x118ac30, use_count() = 4
Local pointer in a thread:
	get() = 0x118ac30, use_count() = 2
Derived::~Derived()
Base::~Base()
All threads completed, the last one deleted Derived.

Example

#include <iostream>
#include <memory>
 
struct MyObj
{
    MyObj() { std::cout << "MyObj constructed\n"; }
 
    ~MyObj() { std::cout << "MyObj destructed\n"; }
};
 
struct Container : std::enable_shared_from_this<Container> // note: public inheritance
{
    std::shared_ptr<MyObj> memberObj;
 
    void CreateMember() { memberObj = std::make_shared<MyObj>(); }
 
    std::shared_ptr<MyObj> GetAsMyObj()
    {
        // Use an alias shared ptr for member
        return std::shared_ptr<MyObj>(shared_from_this(), memberObj.get());
    }
};
 
#define COUT(str) std::cout << '\n' << str << '\n'
 
#define DEMO(...) std::cout << #__VA_ARGS__ << " = " << __VA_ARGS__ << '\n'
 
int main()
{
    COUT( "Creating shared container" );
    std::shared_ptr<Container> cont = std::make_shared<Container>();
    DEMO( cont.use_count() );
    DEMO( cont->memberObj.use_count() );
 
    COUT( "Creating member" );
    cont->CreateMember();
    DEMO( cont.use_count() );
    DEMO( cont->memberObj.use_count() );
 
    COUT( "Creating another shared container" );
    std::shared_ptr<Container> cont2 = cont;
    DEMO( cont.use_count() );
    DEMO( cont->memberObj.use_count() );
    DEMO( cont2.use_count() );
    DEMO( cont2->memberObj.use_count() );
 
    COUT( "GetAsMyObj" );
    std::shared_ptr<MyObj> myobj1 = cont->GetAsMyObj();
    DEMO( myobj1.use_count() );
    DEMO( cont.use_count() );
    DEMO( cont->memberObj.use_count() );
    DEMO( cont2.use_count() );
    DEMO( cont2->memberObj.use_count() );
 
    COUT( "Copying alias obj" );
    std::shared_ptr<MyObj> myobj2 = myobj1;
    DEMO( myobj1.use_count() );
    DEMO( myobj2.use_count() );
    DEMO( cont.use_count() );
    DEMO( cont->memberObj.use_count() );
    DEMO( cont2.use_count() );
    DEMO( cont2->memberObj.use_count() );
 
    COUT( "Resetting cont2" );
    cont2.reset();
    DEMO( myobj1.use_count() );
    DEMO( myobj2.use_count() );
    DEMO( cont.use_count() );
    DEMO( cont->memberObj.use_count() );
 
    COUT( "Resetting myobj2" );
    myobj2.reset();
    DEMO( myobj1.use_count() );
    DEMO( cont.use_count() );
    DEMO( cont->memberObj.use_count() );
 
    COUT( "Resetting cont" );
    cont.reset();
    DEMO( myobj1.use_count() );
    DEMO( cont.use_count() );
}

Output:

Creating shared container
cont.use_count() = 1
cont->memberObj.use_count() = 0
 
Creating member
MyObj constructed
cont.use_count() = 1
cont->memberObj.use_count() = 1
 
Creating another shared container
cont.use_count() = 2
cont->memberObj.use_count() = 1
cont2.use_count() = 2
cont2->memberObj.use_count() = 1
 
GetAsMyObj
myobj1.use_count() = 3
cont.use_count() = 3
cont->memberObj.use_count() = 1
cont2.use_count() = 3
cont2->memberObj.use_count() = 1
 
Copying alias obj
myobj1.use_count() = 4
myobj2.use_count() = 4
cont.use_count() = 4
cont->memberObj.use_count() = 1
cont2.use_count() = 4
cont2->memberObj.use_count() = 1
 
Resetting cont2
myobj1.use_count() = 3
myobj2.use_count() = 3
cont.use_count() = 3
cont->memberObj.use_count() = 1
 
Resetting myobj2
myobj1.use_count() = 2
cont.use_count() = 2
cont->memberObj.use_count() = 1
 
Resetting cont
myobj1.use_count() = 1
cont.use_count() = 0
MyObj destructed

See also

smart pointer with unique object ownership semantics
(class template) [edit]
(C++11)
weak reference to an object managed by std::shared_ptr
(class template) [edit]