😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 C++ 智能指针🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰:
本文未经允许,不得转发!!!
目录
- 🎄一、概述
- 🎄二、std::shared_ptr 的使用
- ✨2.1 std::shared_ptr 构造、析构——创建智能指针
- ✨2.2 std::shared_ptr 赋值运算符(=)
- ✨2.3 std::shared_ptr 指针的访问(get、->、*、bool、use_count)
- ✨2.4 std::shared_ptr 获取删除器
- ✨2.5 std::shared_ptr 指针的重置
- ✨2.6 std::shared_ptr 指针交换
- 🎄三、std::shared_ptr 的实现原理
- ✨3.1 控制块(Control Block)
- ✨3.2 内存布局
- ✨3.3 引用计数操作
- ✨3.4 自定义删除器
- 🎄四、使用的几个注意点
- ✨4.1 不要将栈地址传递给 std::shared_ptr指针
- ✨4.2 std::shared_ptr 指针作为函数参数和返回值
- ✨4.3 优先使用make_shared
- ✨4.4 避免重复接管原始指针
- ✨4.5 避免循环引用
- 🎄五、总结
🎄一、概述
在C++11编程中,智能指针已经成为管理动态内存的标配工具。最开始的智能指针有 std::auto_ptr
,后面 C++11
标准出来后,std::auto_ptr
就废弃了,新增了三个智能指针:std::unique_ptr
、std::shared_ptr
、std::weak_ptr
。
类型 | 特点 |
---|---|
std::unique_ptr | 独占所有权,不可拷贝,只能移动;性能接近裸指针,无额外开销 |
std::shared_ptr | 共享所有权,通过引用计数管理内存;支持拷贝,适合多个对象共享同一资源 |
std::weak_ptr | 弱引用,不增加引用计数;用于解决 shared_ptr 的循环引用问题 |
智能指针 是 C++ 中用于自动化管理动态内存的工具。它们通过封装 裸指针(raw pointer) 并利用 RAII(资源获取即初始化)机制,实现了内存的自动释放,从而帮助开发者避免内存泄漏、悬垂指针等常见内存管理问题。
在 C++11 及之后的代码中,智能指针应成为动态内存管理的默认选择,仅在需要极致性能或与遗留代码交互时使用裸指针。
std::shared_ptr
是 C++11 引入的智能指针,用于管理动态分配对象的生命周期。它通过 引用计数(Reference Counting) 机制,允许多个 shared_ptr
实例共享同一对象的所有权。当最后一个持有对象的 shared_ptr
被销毁时,对象会被自动释放,从而避免内存泄漏。
核心特性
-
共享所有权:多个 shared_ptr 可指向同一对象。
-
自动释放:引用计数归零时自动销毁对象并释放内存。
-
线程安全:引用计数的增减是原子的(但对象访问需手动同步)。
-
支持自定义删除器:允许指定对象销毁时的自定义逻辑。
🎄二、std::shared_ptr 的使用
std::shared_ptr 定义在<memory>
头文件中,这个小节主要介绍其成员函数及其用法:
✨2.1 std::shared_ptr 构造、析构——创建智能指针
std::shared_ptr
的构造函数的函数原型如下:
// 1.默认
constexpr shared_ptr() noexcept;// 2.空指针
constexpr shared_ptr(nullptr_t) : shared_ptr() {}// 3.使用另一个指针进行初始化
template <class U> explicit shared_ptr (U* p);// 4.使用删除器进行初始化
template <class U, class D> shared_ptr (U* p, D del);
template <class D> shared_ptr (nullptr_t p, D del);// 5.使用分配器进行初始化
template <class U, class D, class Alloc> shared_ptr (U* p, D del, Alloc alloc);
template <class D, class Alloc> shared_ptr (nullptr_t p, D del, Alloc alloc);// 6.拷贝构造
template <class U> shared_ptr (const shared_ptr<U>& x) noexcept;
shared_ptr(const shared_ptr&) noexcept = default;// 7.从 weak_ptr 拷贝
template <class U> explicit shared_ptr (const weak_ptr<U>& x);// 8.移动构造函数
shared_ptr (shared_ptr&& x) noexcept;
template <class U> shared_ptr (shared_ptr<U>&& x) noexcept;// 9.从其他类型移动
template <class U> shared_ptr (auto_ptr<U>&& x);
template <class U, class D> shared_ptr (unique_ptr<U,D>&& x);// 10.
template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept;
std::shared_ptr
构造函数:
- 默认构造:创建空 shared_ptr
shared_ptr<int> p;
- 从指针构造:接管原始指针所有权
shared_ptr<int> p(new int(42));
- 拷贝构造:共享所有权,引用计数+1
shared_ptr<int> p2(p1);
- 移动构造:转移所有权,原指针置空
shared_ptr<int> p3(std::move(p2));
- 带删除器的构造:指定自定义销毁逻辑
shared_ptr<FILE> fp(fopen("a.txt", "r"), fclose);
std::shared_ptr
析构函数: 减少引用计数,若计数归零,调用删除器释放资源。
🌰举例子,shared_ptr_constructor.cpp
:
// shared_ptr constructor example
#include <iostream>
#include <memory>struct C {int* data;};int main () {std::shared_ptr<int> p1;std::shared_ptr<int> p2 (nullptr);std::shared_ptr<int> p3 (new int(3));std::shared_ptr<int> p4 (new int, std::default_delete<int>());std::shared_ptr<int> p5 (new int, [](int* p){delete p;}, std::allocator<int>());std::shared_ptr<int> p6 (p5);std::shared_ptr<int> p7 (std::move(p6));std::shared_ptr<int> p8 (std::unique_ptr<int>(new int));std::shared_ptr<C> obj (new C);std::shared_ptr<int> p9 (obj, obj->data);std::cout << "use_count:\n";std::cout << "p1: " << p1.use_count() << '\n';std::cout << "p2: " << p2.use_count() << '\n';std::cout << "p3: " << p3.use_count() << '\n';std::cout << "p4: " << p4.use_count() << '\n';std::cout << "p5: " << p5.use_count() << '\n';std::cout << "p6: " << p6.use_count() << '\n';std::cout << "p7: " << p7.use_count() << '\n';std::cout << "p8: " << p8.use_count() << '\n';std::cout << "p9: " << p9.use_count() << '\n';return 0;
}
运行结果:
✨2.2 std::shared_ptr 赋值运算符(=)
上篇文章 C++ 智能指针 std::unique_ptr 详解 介绍过,unique_ptr
模板类禁用了 拷贝赋值运算符,只保留了 移动赋值运算符。而 shared_ptr
模板类是支持共享的,会议不同的 拷贝赋值运算符、 移动赋值运算符。下面来看看怎么使用。
👉如果对 移动赋值运算符 不清楚的,可以参考这篇文章:一文了解C++11的 移动赋值运算符 。
函数原型:
// 1. 拷贝赋值:共享所有权
shared_ptr& operator= (const shared_ptr& x) noexcept;
template <class U> shared_ptr& operator= (const shared_ptr<U>& x) noexcept;// 2. 移动赋值
shared_ptr& operator= (shared_ptr&& x) noexcept;
template <class U> shared_ptr& operator= (shared_ptr<U>&& x) noexcept;// 3.其他类型指针的移动赋值
template <class U> shared_ptr& operator= (auto_ptr<U>&& x);
template <class U, class D> shared_ptr& operator= (unique_ptr<U,D>&& x);
🌰举例子:
// shared_ptr::operator= example
#include <iostream>
#include <memory>int main () {std::shared_ptr<int> foo;std::shared_ptr<int> bar (new int(10));foo = bar; // copybar = std::make_shared<int> (20); // movestd::unique_ptr<int> unique (new int(30));foo = std::move(unique); // move from unique_ptrstd::cout << "*foo: " << *foo << '\n';std::cout << "*bar: " << *bar << '\n';return 0;
}
运行结果:
✨2.3 std::shared_ptr 指针的访问(get、->、*、bool、use_count)
函数原型:
element_type* get() const noexcept;
element_type* operator->() const noexcept; // 返回的值和 get() 一样
element_type& operator*() const noexcept; // 等价于: *get().
explicit operator bool() const noexcept;
long int use_count() const noexcept; // 获取引用计数
bool unique() const noexcept; // use_count()==1 时为true
🌰举例子:
// shared_ptr_Access.cpp
#include <iostream>
#include <memory>struct C { int a; int b; };int main () {// 1.getint* p = new int (10);std::shared_ptr<int> a (p);if (a.get()==p)std::cout << "a and p point to the same location\n";// three ways of accessing the same address:std::cout << *a.get() << "\n";std::cout << *a << "\n";std::cout << *p << "\n\n";//----------------------------------------------------------------// 2.->std::shared_ptr<C> foo;std::shared_ptr<C> bar (new C);foo = bar;foo->a = 10;bar->b = 20;if (foo) std::cout << "foo: " << foo->a << ' ' << foo->b << '\n';if (bar) std::cout << "bar: " << bar->a << ' ' << bar->b << "\n\n";// 3. *std::shared_ptr<int> foo_3 (new int);std::shared_ptr<int> bar_3 (new int (100));*foo_3 = *bar_3 * 2;std::cout << "foo_3: " << *foo_3 << '\n';std::cout << "bar_3: " << *bar_3 << "\n\n";// 4. boolstd::cout << "foo_3: " << (foo_3?"not null":"null") << "\n\n";// 5.use_countstd::shared_ptr<int> foo_5 (new int);std::shared_ptr<int> bar_5 (foo_5);std::cout << "foo_5 count: " << foo_5.use_count() << ", bar_5 count: " << bar_5.use_count() << "\n\n";// 6.std::shared_ptr<int[]> u_Access4(new int[10]{0,1,2,3,4,5,6,7,8,9});std::cout << "u_Access4: [";for(int i=0; i<10; i++)std::cout << u_Access4[i] << ", ";std::cout << "]" << std::endl;return 0;
}
运行结果:
✨2.4 std::shared_ptr 获取删除器
获取删除器的功能使用的比较少,需要学习的直接看例子。
函数原型:
template <class D, class T> D* get_deleter (const shared_ptr<T>& sp) noexcept;
🌰举例子:
// get_deleter example
#include <iostream>
#include <memory>struct D { // a verbose array deleter:void operator()(int* p) {std::cout << "[deleter called]\n";delete[] p;}
};int main () {std::shared_ptr<int> foo (new int[10],D());int * bar = new int[20];// use foo's deleter to delete bar (which is unmanaged):(*std::get_deleter<D>(foo))(bar);return 0;// foo's deleter called automatically
}
运行结果:
✨2.5 std::shared_ptr 指针的重置
reset
函数会替换被管理的对象.
函数原型:
void reset() noexcept;
template <class U> void reset (U* p);
template <class U, class D> void reset (U* p, D del);
template <class U, class D, class Alloc> void reset (U* p, D del, Alloc alloc);
🌰举例子:
// shared_ptr::reset example
#include <iostream>
#include <memory>int main () {std::shared_ptr<int> sp; // emptysp.reset (new int); // takes ownership of pointer*sp=10;std::cout << *sp << '\n';sp.reset (new int); // deletes managed object, acquires new pointer*sp=20;std::cout << *sp << '\n';sp.reset(); // deletes managed objectreturn 0;
}
运行结果:
✨2.6 std::shared_ptr 指针交换
函数原型:
void swap (shared_ptr& x) noexcept;
功能:与另一个 shared_ptr
指针交换。
🌰举例子:
// shared_ptr_Swap.cpp
#include <iostream>
#include <memory>int main()
{std::shared_ptr<int> u_Swap1(new int(1));std::cout << "u_Swap1=" << u_Swap1.get() << ", value=" << *(u_Swap1.get()) << std::endl;std::shared_ptr<int> u_Swap2(new int(2));std::cout << "u_Swap2=" << u_Swap2.get() << ", value=" << *(u_Swap2.get()) << std::endl;u_Swap1.swap(u_Swap2);std::cout << "after swap:" << std::endl;std::cout << "u_Swap1=" << u_Swap1.get() << ", value=" << *(u_Swap1.get()) << std::endl;std::cout << "u_Swap2=" << u_Swap2.get() << ", value=" << *(u_Swap2.get()) << std::endl;return 0;
}
运行结果:
🎄三、std::shared_ptr 的实现原理
这里先看看 std::shared_ptr 的实现代码。
下面代码是Ubuntu18.04系统截取的,路径是:/usr/include/c++/7/bits/shared_ptr.h
,是 std::shared_ptr 的实现代码,从代码看,继承自 __shared_ptr
。
template<typename _Tp>
class shared_ptr : public __shared_ptr<_Tp>
{template<typename... _Args>using _Constructible = typename enable_if<is_constructible<__shared_ptr<_Tp>, _Args...>::value>::type;template<typename _Arg>using _Assignable = typename enable_if<is_assignable<__shared_ptr<_Tp>&, _Arg>::value, shared_ptr&>::type;public:using element_type = typename __shared_ptr<_Tp>::element_type;#if __cplusplus > 201402L# define __cpp_lib_shared_ptr_weak_type 201606using weak_type = weak_ptr<_Tp>;
#endif/*** @brief Construct an empty %shared_ptr.* @post use_count()==0 && get()==0*/constexpr shared_ptr() noexcept : __shared_ptr<_Tp>() { }shared_ptr(const shared_ptr&) noexcept = default;/*** @brief Construct a %shared_ptr that owns the pointer @a __p.* @param __p A pointer that is convertible to element_type*.* @post use_count() == 1 && get() == __p* @throw std::bad_alloc, in which case @c delete @a __p is called.*/template<typename _Yp, typename = _Constructible<_Yp*>>explicit shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }/*** @brief Construct a %shared_ptr that owns the pointer @a __p* and the deleter @a __d.* @param __p A pointer.* @param __d A deleter.* @post use_count() == 1 && get() == __p* @throw std::bad_alloc, in which case @a __d(__p) is called.** Requirements: _Deleter's copy constructor and destructor must* not throw** __shared_ptr will release __p by calling __d(__p)*/template<typename _Yp, typename _Deleter, typename = _Constructible<_Yp*, _Deleter>>shared_ptr(_Yp* __p, _Deleter __d) : __shared_ptr<_Tp>(__p, std::move(__d)) { }/*** @brief Construct a %shared_ptr that owns a null pointer* and the deleter @a __d.* @param __p A null pointer constant.* @param __d A deleter.* @post use_count() == 1 && get() == __p* @throw std::bad_alloc, in which case @a __d(__p) is called.** Requirements: _Deleter's copy constructor and destructor must* not throw** The last owner will call __d(__p)*/template<typename _Deleter>shared_ptr(nullptr_t __p, _Deleter __d) : __shared_ptr<_Tp>(__p, std::move(__d)) { }/*** @brief Construct a %shared_ptr that owns the pointer @a __p* and the deleter @a __d.* @param __p A pointer.* @param __d A deleter.* @param __a An allocator.* @post use_count() == 1 && get() == __p* @throw std::bad_alloc, in which case @a __d(__p) is called.** Requirements: _Deleter's copy constructor and destructor must* not throw _Alloc's copy constructor and destructor must not* throw.** __shared_ptr will release __p by calling __d(__p)*/template<typename _Yp, typename _Deleter, typename _Alloc,typename = _Constructible<_Yp*, _Deleter, _Alloc>>shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a): __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }/*** @brief Construct a %shared_ptr that owns a null pointer* and the deleter @a __d.* @param __p A null pointer constant.* @param __d A deleter.* @param __a An allocator.* @post use_count() == 1 && get() == __p* @throw std::bad_alloc, in which case @a __d(__p) is called.** Requirements: _Deleter's copy constructor and destructor must* not throw _Alloc's copy constructor and destructor must not* throw.** The last owner will call __d(__p)*/template<typename _Deleter, typename _Alloc>shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a): __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }// Aliasing constructor/*** @brief Constructs a %shared_ptr instance that stores @a __p* and shares ownership with @a __r.* @param __r A %shared_ptr.* @param __p A pointer that will remain valid while @a *__r is valid.* @post get() == __p && use_count() == __r.use_count()** This can be used to construct a @c shared_ptr to a sub-object* of an object managed by an existing @c shared_ptr.** @code* shared_ptr< pair<int,int> > pii(new pair<int,int>());* shared_ptr<int> pi(pii, &pii->first);* assert(pii.use_count() == 2);* @endcode*/template<typename _Yp>shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept: __shared_ptr<_Tp>(__r, __p) { }/*** @brief If @a __r is empty, constructs an empty %shared_ptr;* otherwise construct a %shared_ptr that shares ownership* with @a __r.* @param __r A %shared_ptr.* @post get() == __r.get() && use_count() == __r.use_count()*/template<typename _Yp, typename = _Constructible<const shared_ptr<_Yp>&>>shared_ptr(const shared_ptr<_Yp>& __r) noexcept: __shared_ptr<_Tp>(__r) { }/*** @brief Move-constructs a %shared_ptr instance from @a __r.* @param __r A %shared_ptr rvalue.* @post *this contains the old value of @a __r, @a __r is empty.*/shared_ptr(shared_ptr&& __r) noexcept : __shared_ptr<_Tp>(std::move(__r)) { }/*** @brief Move-constructs a %shared_ptr instance from @a __r.* @param __r A %shared_ptr rvalue.* @post *this contains the old value of @a __r, @a __r is empty.*/template<typename _Yp, typename = _Constructible<shared_ptr<_Yp>>>shared_ptr(shared_ptr<_Yp>&& __r) noexcept: __shared_ptr<_Tp>(std::move(__r)) { }/*** @brief Constructs a %shared_ptr that shares ownership with @a __r* and stores a copy of the pointer stored in @a __r.* @param __r A weak_ptr.* @post use_count() == __r.use_count()* @throw bad_weak_ptr when __r.expired(),* in which case the constructor has no effect.*/template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>explicit shared_ptr(const weak_ptr<_Yp>& __r): __shared_ptr<_Tp>(__r) { }#if _GLIBCXX_USE_DEPRECATEDtemplate<typename _Yp, typename = _Constructible<auto_ptr<_Yp>>>shared_ptr(auto_ptr<_Yp>&& __r);
#endif// _GLIBCXX_RESOLVE_LIB_DEFECTS// 2399. shared_ptr's constructor from unique_ptr should be constrainedtemplate<typename _Yp, typename _Del, typename = _Constructible<unique_ptr<_Yp, _Del>>>shared_ptr(unique_ptr<_Yp, _Del>&& __r): __shared_ptr<_Tp>(std::move(__r)) { }#if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED// This non-standard constructor exists to support conversions that// were possible in C++11 and C++14 but are ill-formed in C++17.// If an exception is thrown this constructor has no effect.template<typename _Yp, typename _Del,_Constructible<unique_ptr<_Yp, _Del>, __sp_array_delete>* = 0>shared_ptr(unique_ptr<_Yp, _Del>&& __r): __shared_ptr<_Tp>(std::move(__r), __sp_array_delete()) { }
#endif/*** @brief Construct an empty %shared_ptr.* @post use_count() == 0 && get() == nullptr*/constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }shared_ptr& operator=(const shared_ptr&) noexcept = default;template<typename _Yp>_Assignable<const shared_ptr<_Yp>&>operator=(const shared_ptr<_Yp>& __r) noexcept{this->__shared_ptr<_Tp>::operator=(__r);return *this;}#if _GLIBCXX_USE_DEPRECATEDtemplate<typename _Yp>_Assignable<auto_ptr<_Yp>>operator=(auto_ptr<_Yp>&& __r){this->__shared_ptr<_Tp>::operator=(std::move(__r));return *this;}
#endifshared_ptr& operator=(shared_ptr&& __r) noexcept{this->__shared_ptr<_Tp>::operator=(std::move(__r));return *this;}template<class _Yp> _Assignable<shared_ptr<_Yp>>operator=(shared_ptr<_Yp>&& __r) noexcept{this->__shared_ptr<_Tp>::operator=(std::move(__r));return *this;}template<typename _Yp, typename _Del>_Assignable<unique_ptr<_Yp, _Del>>operator=(unique_ptr<_Yp, _Del>&& __r){this->__shared_ptr<_Tp>::operator=(std::move(__r));return *this;}private:// This constructor is non-standard, it is used by allocate_shared.template<typename _Alloc, typename... _Args>shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,_Args&&... __args): __shared_ptr<_Tp>(__tag, __a, std::forward<_Args>(__args)...){ }template<typename _Yp, typename _Alloc, typename... _Args>friend shared_ptr<_Yp>allocate_shared(const _Alloc& __a, _Args&&... __args);// This constructor is non-standard, it is used by weak_ptr::lock().shared_ptr(const weak_ptr<_Tp>& __r, std::nothrow_t): __shared_ptr<_Tp>(__r, std::nothrow) { }friend class weak_ptr<_Tp>;
};
✨3.1 控制块(Control Block)
每个 shared_ptr
关联一个控制块,包含:
-
引用计数(use_count):跟踪当前共享所有权的 shared_ptr 数量。
-
弱计数(weak_count):跟踪 weak_ptr 的数量。
-
删除器(Deleter):销毁对象的逻辑(默认为 delete)。
-
分配器(Allocator):内存分配策略(通常由 make_shared 管理)。
✨3.2 内存布局
make_shared
优化:对象与控制块一次性分配,减少内存碎片。
| Control Block (ref counts) | Managed Object |
✨3.3 引用计数操作
-
拷贝构造:递增引用计数。
-
析构:递减引用计数,若归零则调用删除器释放对象,若弱计数也为零则释放控制块。
✨3.4 自定义删除器
std::shared_ptr 支持自定义删除器,这使得它可以管理不仅仅是new分配的内存:
// 使用自定义删除器管理文件指针
auto file_deleter = [](FILE* fp) { if(fp) fclose(fp); };
std::shared_ptr<FILE, decltype(file_deleter)> file_ptr(fopen("test.txt", "r"), file_deleter);
🎄四、使用的几个注意点
✨4.1 不要将栈地址传递给 std::shared_ptr指针
std::shared_ptr 指针会在销毁时调用默认的删除器销毁指针,默认的删除器一般是 delete
或 delete[]
,如果将栈地址给到 std::shared_ptr指针后,对象销毁时会出错,看下面例子:
// shared_ptr_Stack.cpp
#include <iostream>
#include <memory>int main()
{int a = 5;std::cout << "&a=" << &a << std::endl;std::shared_ptr<int> u_Stack(&a);std::cout << "u_Stack=" << u_Stack.get() << ", value=" << *(u_Stack.get()) << std::endl;return 0;
}
运行结果:
✨4.2 std::shared_ptr 指针作为函数参数和返回值
作为函数参数:需要先将指针转换为右值。
作为函数返回值:因为非引用返回值本身就是右值,可以直接返回。
举例子:
// shared_ptr_Func.cpp
#include <iostream>
#include <memory>struct D { // a verbose array deleter:void operator()(int* p) {if(p){delete p;std::cout << "delete." << " p=" << p << std::endl;}}
};// 作为参数引用计数加1
void use_count_add(std::shared_ptr<int> ptr) {std::cout << "ptr=" << ptr.get() << ", count=" << ptr.use_count() << std::endl;
} // ptr自动释放,引用计数减一// 作为返回值引用计数不变,应该是调用了移动赋值运算符
std::shared_ptr<int> create_int(int value) {std::shared_ptr<int> uRet(new int(value));std::cout << "uRet=" << uRet.get() << ", count=" << uRet.use_count() << std::endl;return uRet;
}int main()
{std::shared_ptr<int> u_Param(new int(1), D());std::cout << "u_Param=" << u_Param.get() << ", value=" << *(u_Param.get()) << std::endl;use_count_add(u_Param); // 引用计数加1std::cout << "u_Param=" << u_Param.get() << ", count=" << u_Param.use_count() << std::endl;std::shared_ptr<int> u_Return = create_int(3);std::cout << "u_Return=" << u_Return.get() << ", count=" << u_Return.use_count() << std::endl;return 0;
}
运行结果:
✨4.3 优先使用make_shared
C++11就已经有了 make_shared
函数,创建对象时,应该优先使用 make_shared
,提升性能与异常安全。
函数原型:
template <class T, class... Args> shared_ptr<T> make_shared (Args&&... args);
make_shared的功能时,分配并构造一个T类型的对象,将参数传递给其构造函数,并返回一个shared_ptr类型的对象。该对象拥有并存储指向它的指针(使用计数为1)。
举例子:
// make_shared example
#include <iostream>
#include <memory>int main () {std::shared_ptr<int> foo = std::make_shared<int> (10);// same as:std::shared_ptr<int> foo2 (new int(10));auto bar = std::make_shared<int> (20);auto baz = std::make_shared<std::pair<int,int>> (30,40);std::cout << "*foo: " << *foo << '\n';std::cout << "*bar: " << *bar << '\n';std::cout << "*baz: " << baz->first << ' ' << baz->second << '\n';return 0;
}
运行结果:
✨4.4 避免重复接管原始指针
始终通过 shared_ptr 传递所有权。
int* raw = new int(10);
shared_ptr<int> p1(raw);
// shared_ptr<int> p2(raw); // 错误!双重释放
✨4.5 避免循环引用
问题:两个 shared_ptr 互相引用,导致计数无法归零。
解决:使用 weak_ptr 打破循环。
class B;
class A {shared_ptr<B> b_ptr;
};
class B {weak_ptr<A> a_ptr; // 使用 weak_ptr
};
🎄五、总结
std::shared_ptr 是 C++ 内存管理的核心工具之一,正确使用可显著降低内存泄漏风险。理解其成员函数、引用计数机制及使用场景,能帮助开发者编写更安全、高效的代码。对于复杂场景,结合 weak_ptr 和 make_shared,可进一步提升程序的健壮性。
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
参考:
C++ 智能指针详解:std::unique_ptr、std::shared_ptr 和 std::weak_ptr
https://cplusplus.com/reference/memory/shared_ptr/