std::shared_ptr 是 c++++ 中用于管理动态分配对象的智能指针,其核心机制是引用计数。1. 它允许多个 shared_ptr 共享同一个对象,当最后一个 shared_ptr 被销毁或重置时,对象会被自动删除;2. 定义 shared_ptr 最推荐的方法是使用 std::make_shared 函数,它在分配内存的同时初始化对象并创建智能指针;3. 使用 shared_ptr 时需要注意避免混用裸指针、防止循环引用(可使用 std::weak_ptr 解决)以及考虑其性能开销;4. 常见使用场景包括共享资源管理、容器中保存动态对象以及回调函数中传递对象以防止提前释放。
std::shared_ptr 是 c++ 中智能指针的一种,用来管理动态分配的对象(比如用 new 创建的对象),它通过引用计数的方式自动管理内存的释放。简单来说,就是多个 shared_ptr 可以共享同一个对象,当最后一个指向该对象的 shared_ptr 被销毁或重置时,对象会被自动删除。
什么是 std::shared_ptr?
shared_ptr 的核心机制是引用计数。每当一个新的 shared_ptr 指向某个对象时,引用计数加一;当某个 shared_ptr 不再指向这个对象(比如被销毁或赋值为其他对象)时,引用计数减一。当引用计数变为0时,说明没有 shared_ptr 在使用这个对象了,系统就会自动释放这块内存。
这种机制有效避免了内存泄漏,也比手动调用 delete 更安全。
立即学习“C++免费学习笔记(深入)”;
如何定义一个 std::shared_ptr?
定义 shared_ptr 最常用的方法是使用 std::make_shared 函数,这是推荐的做法:
auto ptr = std::make_shared<int>(42);
上面这行代码做了三件事:
- 分配了一个 int 类型的内存空间
- 初始化为 42
- 创建一个 shared_ptr
来管理这块内存
也可以用构造函数直接绑定到已有的指针上,但这种方式要特别小心,容易出错,不建议新手使用:
int* raw = new int(42); std::shared_ptr<int> ptr(raw); // 不推荐,除非你很清楚自己在做什么
使用 shared_ptr 时要注意什么?
-
不要混用裸指针和 shared_ptr
- 如果你已经用 shared_ptr 管理了一块内存,就不要再用普通指针去操作它,否则可能造成重复释放或者访问已释放内存。
-
循环引用问题
- 如果两个对象各自持有对方的 shared_ptr,会导致引用计数永远不为0,从而造成内存泄漏。这时候可以用 std::weak_ptr 来打破循环。
-
性能考虑
- shared_ptr 的引用计数操作是线程安全的,但也有一定开销。如果你不需要共享所有权,优先使用 std::unique_ptr。
实际中怎么用?
常见的使用场景包括:
- 多个对象共享同一份资源,比如缓存、配置信息等
- 容器中保存动态分配的对象,避免手动释放
- 回调函数中传递对象,防止对象提前被释放
举个例子:
#include <iostream> #include <memory> #include <vector> struct Data { int value; Data(int v) : value(v) { std::cout << "Constructedn"; } ~Data() { std::cout << "Destroyedn"; } }; int main() { std::vector<std::shared_ptr<Data>> vec; auto d = std::make_shared<Data>(10); vec.push_back(d); vec.push_back(d); std::cout << "Use count: " << d.use_count() << "n"; // 输出 3 } // 离开作用域后,所有 shared_ptr 被销毁,引用计数归零,对象被释放
在这个例子里,d 和 vec 中的两个元素共同持有同一个 Data 对象,引用计数会变成3,当它们都离开作用域后才会释放内存。
基本上就这些。掌握 shared_ptr 的基本用法和常见陷阱,就能在大多数项目中安全地使用它了。