欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > shared_ptr和 weak_ptr的详细介绍

shared_ptr和 weak_ptr的详细介绍

2025/4/1 18:37:09 来源:https://blog.csdn.net/froxy/article/details/146709937  浏览:    关键词:shared_ptr和 weak_ptr的详细介绍

关于 shared_ptrweak_ptr 的详细介绍及使用示例:


1. shared_ptr(共享所有权智能指针)

核心特性
  • 引用计数:记录当前有多少个 shared_ptr 共享同一个对象。
  • 自动释放:当引用计数归零时,自动释放对象内存。
  • 线程安全:引用计数的增减是原子操作(但对象本身的访问需自行同步)。
基本用法
#include <memory>
#include <iostream>class MyClass {
public:MyClass() { std::cout << "MyClass 构造\n"; }~MyClass() { std::cout << "MyClass 析构\n"; }void print() { std::cout << "Hello\n"; }
};int main() {// 创建 shared_ptr(推荐使用 make_shared)std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();// 共享所有权(引用计数+1)std::shared_ptr<MyClass> ptr2 = ptr1;// 使用 -> 操作符访问成员ptr1->print(); // 输出: Hello// 引用计数查看(调试用)std::cout << "引用计数: " << ptr1.use_count() << std::endl; // 输出: 2// ptr1 和 ptr2 离开作用域,引用计数归零,对象自动析构return 0;
}
输出结果
MyClass 构造
Hello
引用计数: 2
MyClass 析构

2. weak_ptr(弱引用智能指针)

核心特性
  • 不增加引用计数:仅观察对象,不影响其生命周期。
  • 需转换为 shared_ptr:通过 lock() 获取临时 shared_ptr 来访问对象。
  • 解决循环引用:打破 shared_ptr 的循环依赖,避免内存泄漏。

3. 循环引用问题与 weak_ptr 解决方案

循环引用示例
#include <memory>
#include <iostream>
class Node {
public:std::shared_ptr<Node> next;Node() { std::cout << "Node 构造\n"; }~Node() { std::cout << "Node 析构\n"; }
};int main() {auto node1 = std::make_shared<Node>();auto node2 = std::make_shared<Node>();node1->next = node2; // node2 引用计数=2node2->next = node1; // node1 引用计数=2// 退出作用域后,node1/node2 引用计数=1,无法释放!return 0;
}
输出结果(内存泄漏)
Node 构造
Node 构造
使用 weak_ptr 解决循环引用
#include <memory>
#include <iostream>
class SafeNode {
public:std::weak_ptr<SafeNode> next; // 使用 weak_ptrSafeNode() { std::cout << "SafeNode 构造\n"; }~SafeNode() { std::cout << "SafeNode 析构\n"; }
};int main() {auto node1 = std::make_shared<SafeNode>();auto node2 = std::make_shared<SafeNode>();node1->next = node2;node2->next = node1;// 退出作用域后,引用计数归零,正确析构return 0;
}
输出结果
SafeNode 构造
SafeNode 构造
SafeNode 析构
SafeNode 析构

4. weak_ptr 的典型使用场景

(1) 访问共享对象前检查存活状态
#include <memory>
#include <iostream>class MyClass {
public:MyClass() { std::cout << "MyClass 构造\n"; }~MyClass() { std::cout << "MyClass 析构\n"; }void print() { std::cout << "Hello\n"; }
};void checkObject(std::weak_ptr<MyClass> weak) {if (auto shared = weak.lock()) { // 转换为 shared_ptrshared->print();} else {std::cout << "对象已被释放\n";}
}int main() {std::weak_ptr<MyClass> weak;{auto shared = std::make_shared<MyClass>();weak = shared;checkObject(weak); // 输出: Hello}checkObject(weak); // 输出: 对象已被释放return 0;
}

输出结果

MyClass 构造
Hello
MyClass 析构
对象已被释放
(2) 观察者模式(缓存)
class DataCache {std::weak_ptr<MyClass> cachedData;
public:void updateCache(std::shared_ptr<MyClass> data) {cachedData = data;}void useCache() {if (auto data = cachedData.lock()) {data->print();} else {std::cout << "缓存无效\n";}}
};

5. shared_ptrweak_ptr 操作总结

操作shared_ptrweak_ptr
所有权拥有对象所有权仅观察对象
引用计数影响增加不影响
访问对象直接通过 ->*需调用 lock() 获取 shared_ptr
检查有效性if (ptr)if (weak.expired())lock()

6. 最佳实践

  1. 优先使用 make_shared:更高效(单次内存分配对象+控制块)。
  2. 避免循环引用:成员指针优先考虑 weak_ptr
  3. 不要用 new 初始化:直接传递裸指针可能导致多次释放。
  4. 谨慎传递 shared_ptr:仅在需要共享所有权时传递,否则传递原始引用或指针。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词