跳到主要内容

std::shared_ptr

定义于头文件 <memory>

声明

自 C++11 起
template< class T > class shared_ptr;

描述

std::shared_ptr 是一个智能指针,它通过指针保留对象的共享所有权。

多个 shared_ptr 对象可以拥有同一个对象。当以下任一情况发生时,对象将被销毁并解除内存分配:

  • 最后一个拥有该对象的 shared_ptr 被销毁;
  • 最后一个拥有该对象的 shared_ptr 通过 operator=reset() 被赋值给另一个指针。
  • 对象使用 delete 表达式或在构造 shared_ptr 时提供的自定义删除器销毁。

shared_ptr 可以共享对象的所有权,同时存储指向另一个对象的指针。此功能可用于指向成员对象,同时拥有它们所属的对象。存储的指针是 get()、解引用和比较运算符访问的指针。当使用计数达到零时,托管指针是传递给删除器的指针。

shared_ptr 也可以不拥有任何对象,在这种情况下它被称为空(如果使用别名构造函数创建,空的 shared_ptr 可能有一个非 null 存储指针)。

shared_ptr 的所有特化都满足 CopyConstructibleCopyAssignableLessThanComparable 的要求,并且可以上下文转换为 bool

所有成员函数(包括拷贝构造函数和拷贝赋值)都可以由多个线程在 shared_ptr 的不同实例上调用,而无需额外同步,即使这些实例是拷贝并且共享同一对象的所有权。如果多个执行线程在不同步的情况下访问同一 shared_ptr 实例,并且其中任何一个访问使用了 shared_ptr 的非 const 成员函数,则会发生数据竞争;可以使用原子函数的 shared_ptr 重载来防止数据竞争。

成员类型

pubelement_typeT (直到 C++17)
std::remove_extent_t<T> (自 C++17 起)
pubweak_type
(自 C++17 起)
std::weak_ptr<T>

成员函数

pub(构造函数)构造新的 shared_ptr
(公共成员函数)
pub(析构函数)如果没有更多的 shared_ptr 链接到它,则销毁所拥有的对象
(公共成员函数)
puboperator=赋值 shared_ptr
(公共成员函数)

修改器

pubreset替换托管对象
(公共成员函数)
pubswap交换托管对象
(公共成员函数)

观察者

pubget返回存储的指针
(公共成员函数)
puboperator*解引用存储的指针
(公共成员函数)
puboperator_at
(C++17)
提供对存储数组的索引访问
(公共成员函数)
pubuse_count返回引用同一托管对象的 shared_ptr 对象的数量
(公共成员函数)
pubunique
(直到 C++20)
检查托管对象是否仅由当前 shared_ptr 实例管理
(公共成员函数)
puboperator bool检查存储的指针是否不为空
(公共成员函数)
pubowner_before提供基于所有者的 shared_ptr 排序
(公共成员函数)

非成员函数

pubmake_shared
make_shared_for_overwrite (C++20)
创建管理新对象的 shared_ptr
(函数模板)
puballocate_shared
allocate_shared_for_overwrite (C++20)
创建使用分配器分配的新对象的 shared_ptr
(函数模板)
pubstatic_pointer_cast
dynamic_pointer_cast
const_pointer_cast
reinterpret_pointer_cast (C++17)
对存储的指针应用 static_cast、dynamic_cast、const_cast 或 reinterpret_cast
(函数模板)
pubget_deleter返回指定类型的删除器(如果拥有)
(函数模板)
puboperator==
operator!= (C++20 中移除)
operator< (C++20 中移除)
operator<= (C++20 中移除)
operator> (C++20 中移除)
operator>= (C++20 中移除)
operator<=> (C++20)
与另一个 shared_ptr 或 nullptr 进行比较
(函数模板)
puboperator<<(std::shared_ptr)将存储的指针值输出到输出流
(函数模板)
pubstd::swap(std::shared_ptr) (C++11)特化 std::swap 算法
(函数模板)
pubstd::atomic_is_lock_free(std::shared_ptr)
std::atomic_load(std::shared_ptr)
std::atomic_load_explicit(std::shared_ptr)
std::atomic_store(std::shared_ptr)
std::atomic_store_explicit(std::shared_ptr)
std::atomic_exchange(std::shared_ptr)
std::atomic_exchange_explicit(std::shared_ptr)
std::atomic_compare_exchange_weak(std::shared_ptr)
std::atomic_compare_exchange_strong(std::shared_ptr)
std::atomic_compare_exchange_weak_explicit(std::shared_ptr)
std::atomic_compare_exchange_strong_explicit(std::shared_ptr)
(所有在 C++20 中已弃用)
特化 std::shared_ptr 的原子操作
(函数模板)

帮助类

pubstd::atomic<std::shared_ptr>(C++20)原子共享指针
(类模板特化)
pubstd::hash<std::shared_ptr>(C++11)对 std::shared_ptr 的哈希支持
(类模板特化)

推导指南 (自 C++17 起)

备注

对象的所有权只能通过将其值拷贝构造或拷贝赋值给另一个 shared_ptr 来与另一个 shared_ptr 共享。使用另一个 shared_ptr 拥有的原始底层指针构造新的 shared_ptr 会导致未定义行为。

std::shared_ptr 可以与不完整类型 T 一起使用。但是,从原始指针构造函数(template<class Y> shared_ptr(Y*))和 template<class Y> void reset(Y*) 成员函数只能与指向完整类型的指针一起调用(注意 std::unique_ptr 可以从指向不完整类型的原始指针构造)。

std::shared_ptr<T> 中的 T 可以是函数类型:在这种情况下,它管理函数指针,而不是对象指针。这有时用于在任何函数被引用时保持动态库或插件加载

void del(void(*)()) {}

void fun() {}

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

实现注意事项

在典型实现中,shared_ptr 只持有两个指针

  • 存储的指针(由 get() 返回);
  • 指向控制块的指针。

控制块是一个动态分配的对象,它包含

  • 指向托管对象的指针或托管对象本身;
  • 删除器(类型擦除);
  • 分配器(类型擦除);
  • 拥有托管对象的 shared_ptr 数量;
  • 引用托管对象的 weak_ptr 数量。

当通过调用 std::make_sharedstd::allocate_shared 创建 shared_ptr 时,控制块和托管对象的内存通过一次分配创建。托管对象在控制块的数据成员中就地构造。当通过 shared_ptr 构造函数之一创建 shared_ptr 时,托管对象和控制块必须单独分配。在这种情况下,控制块存储指向托管对象的指针。

shared_ptr 直接持有的指针是由 get() 返回的指针,而控制块持有的指针/对象是当共享所有者数量达到零时将被删除的指针/对象。这些指针不一定相等。

shared_ptr 的析构函数会递减控制块的共享所有者数量。如果该计数器达到零,控制块会调用托管对象的析构函数。控制块直到 std::weak_ptr 计数器也达到零才解除自身分配。

在现有实现中,如果有指向相同控制块的共享指针,则弱指针的数量会增加 ([1], [2])。

为了满足线程安全要求,引用计数器通常使用类似于 std::atomic::fetch_addstd::memory_order_relaxed 的方式递增(递减需要更强的顺序以安全销毁控制块)。

示例 1

#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";
}
可能结果
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.

示例 2

#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() );
}
可能结果
Creating shared container
cont.use_count() = 1
cont->memberObj.use_count() = 0
MyObj constructed

Creating member
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

std::shared_ptr

定义于头文件 <memory>

声明

自 C++11 起
template< class T > class shared_ptr;

描述

std::shared_ptr 是一个智能指针,它通过指针保留对象的共享所有权。

多个 shared_ptr 对象可以拥有同一个对象。当以下任一情况发生时,对象将被销毁并解除内存分配:

  • 最后一个拥有该对象的 shared_ptr 被销毁;
  • 最后一个拥有该对象的 shared_ptr 通过 operator=reset() 被赋值给另一个指针。
  • 对象使用 delete 表达式或在构造 shared_ptr 时提供的自定义删除器销毁。

shared_ptr 可以共享对象的所有权,同时存储指向另一个对象的指针。此功能可用于指向成员对象,同时拥有它们所属的对象。存储的指针是 get()、解引用和比较运算符访问的指针。当使用计数达到零时,托管指针是传递给删除器的指针。

shared_ptr 也可以不拥有任何对象,在这种情况下它被称为空(如果使用别名构造函数创建,空的 shared_ptr 可能有一个非 null 存储指针)。

shared_ptr 的所有特化都满足 CopyConstructibleCopyAssignableLessThanComparable 的要求,并且可以上下文转换为 bool

所有成员函数(包括拷贝构造函数和拷贝赋值)都可以由多个线程在 shared_ptr 的不同实例上调用,而无需额外同步,即使这些实例是拷贝并且共享同一对象的所有权。如果多个执行线程在不同步的情况下访问同一 shared_ptr 实例,并且其中任何一个访问使用了 shared_ptr 的非 const 成员函数,则会发生数据竞争;可以使用原子函数的 shared_ptr 重载来防止数据竞争。

成员类型

pubelement_typeT (直到 C++17)
std::remove_extent_t<T> (自 C++17 起)
pubweak_type
(自 C++17 起)
std::weak_ptr<T>

成员函数

pub(构造函数)构造新的 shared_ptr
(公共成员函数)
pub(析构函数)如果没有更多的 shared_ptr 链接到它,则销毁所拥有的对象
(公共成员函数)
puboperator=赋值 shared_ptr
(公共成员函数)

修改器

pubreset替换托管对象
(公共成员函数)
pubswap交换托管对象
(公共成员函数)

观察者

pubget返回存储的指针
(公共成员函数)
puboperator*解引用存储的指针
(公共成员函数)
puboperator_at
(C++17)
提供对存储数组的索引访问
(公共成员函数)
pubuse_count返回引用同一托管对象的 shared_ptr 对象的数量
(公共成员函数)
pubunique
(直到 C++20)
检查托管对象是否仅由当前 shared_ptr 实例管理
(公共成员函数)
puboperator bool检查存储的指针是否不为空
(公共成员函数)
pubowner_before提供基于所有者的 shared_ptr 排序
(公共成员函数)

非成员函数

pubmake_shared
make_shared_for_overwrite (C++20)
创建管理新对象的 shared_ptr
(函数模板)
puballocate_shared
allocate_shared_for_overwrite (C++20)
创建使用分配器分配的新对象的 shared_ptr
(函数模板)
pubstatic_pointer_cast
dynamic_pointer_cast
const_pointer_cast
reinterpret_pointer_cast (C++17)
对存储的指针应用 static_cast、dynamic_cast、const_cast 或 reinterpret_cast
(函数模板)
pubget_deleter返回指定类型的删除器(如果拥有)
(函数模板)
puboperator==
operator!= (C++20 中移除)
operator< (C++20 中移除)
operator<= (C++20 中移除)
operator> (C++20 中移除)
operator>= (C++20 中移除)
operator<=> (C++20)
与另一个 shared_ptr 或 nullptr 进行比较
(函数模板)
puboperator<<(std::shared_ptr)将存储的指针值输出到输出流
(函数模板)
pubstd::swap(std::shared_ptr) (C++11)特化 std::swap 算法
(函数模板)
pubstd::atomic_is_lock_free(std::shared_ptr)
std::atomic_load(std::shared_ptr)
std::atomic_load_explicit(std::shared_ptr)
std::atomic_store(std::shared_ptr)
std::atomic_store_explicit(std::shared_ptr)
std::atomic_exchange(std::shared_ptr)
std::atomic_exchange_explicit(std::shared_ptr)
std::atomic_compare_exchange_weak(std::shared_ptr)
std::atomic_compare_exchange_strong(std::shared_ptr)
std::atomic_compare_exchange_weak_explicit(std::shared_ptr)
std::atomic_compare_exchange_strong_explicit(std::shared_ptr)
(所有在 C++20 中已弃用)
特化 std::shared_ptr 的原子操作
(函数模板)

帮助类

pubstd::atomic<std::shared_ptr>(C++20)原子共享指针
(类模板特化)
pubstd::hash<std::shared_ptr>(C++11)对 std::shared_ptr 的哈希支持
(类模板特化)

推导指南 (自 C++17 起)

备注

对象的所有权只能通过将其值拷贝构造或拷贝赋值给另一个 shared_ptr 来与另一个 shared_ptr 共享。使用另一个 shared_ptr 拥有的原始底层指针构造新的 shared_ptr 会导致未定义行为。

std::shared_ptr 可以与不完整类型 T 一起使用。但是,从原始指针构造函数(template<class Y> shared_ptr(Y*))和 template<class Y> void reset(Y*) 成员函数只能与指向完整类型的指针一起调用(注意 std::unique_ptr 可以从指向不完整类型的原始指针构造)。

std::shared_ptr<T> 中的 T 可以是函数类型:在这种情况下,它管理函数指针,而不是对象指针。这有时用于在任何函数被引用时保持动态库或插件加载

void del(void(*)()) {}

void fun() {}

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

实现注意事项

在典型实现中,shared_ptr 只持有两个指针

  • 存储的指针(由 get() 返回);
  • 指向控制块的指针。

控制块是一个动态分配的对象,它包含

  • 指向托管对象的指针或托管对象本身;
  • 删除器(类型擦除);
  • 分配器(类型擦除);
  • 拥有托管对象的 shared_ptr 数量;
  • 引用托管对象的 weak_ptr 数量。

当通过调用 std::make_sharedstd::allocate_shared 创建 shared_ptr 时,控制块和托管对象的内存通过一次分配创建。托管对象在控制块的数据成员中就地构造。当通过 shared_ptr 构造函数之一创建 shared_ptr 时,托管对象和控制块必须单独分配。在这种情况下,控制块存储指向托管对象的指针。

shared_ptr 直接持有的指针是由 get() 返回的指针,而控制块持有的指针/对象是当共享所有者数量达到零时将被删除的指针/对象。这些指针不一定相等。

shared_ptr 的析构函数会递减控制块的共享所有者数量。如果该计数器达到零,控制块会调用托管对象的析构函数。控制块直到 std::weak_ptr 计数器也达到零才解除自身分配。

在现有实现中,如果有指向相同控制块的共享指针,则弱指针的数量会增加 ([1], [2])。

为了满足线程安全要求,引用计数器通常使用类似于 std::atomic::fetch_addstd::memory_order_relaxed 的方式递增(递减需要更强的顺序以安全销毁控制块)。

示例 1

#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";
}
可能结果
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.

示例 2

#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() );
}
可能结果
Creating shared container
cont.use_count() = 1
cont->memberObj.use_count() = 0
MyObj constructed

Creating member
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