智能指针 weak_ptr

weak_ptr:
 weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况.
用法:
 weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。
 使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。
 weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr.
实例:
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>
using namespace boost;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
 shared_ptr<int> sp(new int(10));
 assert(sp.use_count() == 1);
 weak_ptr<int> wp(sp); //从shared_ptr创建weak_ptr
 assert(wp.use_count() == 1);
 if (!wp.expired())//判断weak_ptr观察的对象是否失效
 {
  shared_ptr<int> sp2 = wp.lock();//获得一个shared_ptr
  *sp2 = 100;
  assert(wp.use_count() == 2);
 }
 assert(wp.use_count() == 1);
 return 0;
}

获得this的shared_ptr
 weak_ptr的一个重要用途是获得this指针的shared_ptr,使对象自己能够生产shared_ptr管理自己;对象使用weak_ptr观测this指针,这并不影响引用计数,在需要的时候就调用lock()函数,返回一个符合要求的shared_ptr共外界使用.
 这个解决方案被实现为一个惯用法,在头文件<boost/enable_shared_from_this.hpp>定义了一个助手类enable_shared_from_this<T>,它的声明摘要如下:
template<class T>
class enable_shared_from_this
{
public:
 shared_ptr<T> shared_from_this();
}
使用的时候只需要让像被shared_ptr管理的类从它继承即可,成员函数shared_from_this()会返回this的shared_ptr.例如:
#include <boost/make_shared.hpp>
#include <boost/enable_shared_from_this.hpp>
using namespace boost;
using namespace std;
class self_shared: public enable_shared_from_this<self_shared>
{
public:
 self_shared(int n):x(n){}
 int x;
 void print()
 {cout<<" self_shared:"<<x<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
 shared_ptr<self_shared> sp = make_shared<self_shared>(314);
 sp->print();
 shared_ptr<self_shared> p = sp->shared_from_this();
 p->x = 1000;
 p->print();
 return 0;
}

注意:千万不能从一个普通对象(非shared_ptr)使用shared_from_this()获去shared_ptr,例如
self_shared ss;
shared_ptr<self_shared> p = ss.shared_from_this();//错误!
在运行时会导致shared_ptr析构时企图删除一个栈上分配的对象,发生未定义行为。

<think>嗯,用户想了解C++中的weak_ptr的用法以及它如何避免循环引用。首先,我需要回忆一下相关的知识。weak_ptr是C++11引入的智能指针之一,通常与shared_ptr配合使用。它的主要作用应该是解决shared_ptr之间的循环引用问题,避免内存泄漏。 根据引用中的内容,比如引用[2]提到weak_ptr不会增加引用计数,这应该是因为它只是观察对象,而不拥有所有权。那循环引用具体是怎么发生的呢?比如两个类互相持有对方的shared_ptr,这样它们的引用计数永远不会归零,导致无法释放内存。这时候就需要用weak_ptr来替换其中一个,打破循环。 接下来,用户可能想知道如何使用weak_ptr。根据引用[5],weak_ptr需要从shared_ptr构造,或者通过赋值来获取。使用时,可以通过lock()方法获取一个临时的shared_ptr来访问对象,这样可以确保在使用时对象仍然存在。例如,当需要访问weak_ptr指向的对象时,应该先调用lock()检查是否有效。 另外,weak_ptr的应用场景有哪些?比如观察者模式中,观察者持有被观察者的weak_ptr,这样不会影响被观察者的生命周期。或者在缓存中,当主对象不再需要缓存项时,缓存可以使用weak_ptr来保存,这样当主对象销毁时,缓存项可以自动释放。 然后需要解释如何用weak_ptr解决循环引用的问题。比如,在父子类结构中,如果父节点持有子节点的shared_ptr,而子节点又持有父节点的shared_ptr,就会形成循环。这时候可以将子节点中的父节点指针改为weak_ptr,这样父节点的引用计数不会被子节点增加,当外部释放父节点时,其引用计数会归零,从而正确释放内存。 可能还需要注意weak_ptr本身不管理生命周期,因此在使用前必须检查有效性。lock()方法返回的shared_ptr如果为空,说明对象已经被释放,这时候就不能再访问了。 总结一下,回答应该包括weak_ptr的基本用法、如何解决循环引用、使用时的注意事项以及适用场景。同时根据用户要求,生成相关的问题,比如性能影响、多线程安全、与原始指针的比较等。</think>### C++ weak_ptr 使用方法及避免循环引用 #### 1. weak_ptr 的基本用法 `std::weak_ptr` 是 C++11 引入的智能指针,需与 `std::shared_ptr` 配合使用。它不直接管理对象的生命周期,而是“观察”由 `shared_ptr` 管理的对象,且**不会增加引用计数**。 - **构造方法**: ```cpp auto shared = std::make_shared<int>(42); std::weak_ptr<int> weak(shared); // 通过 shared_ptr 构造 weak_ptr ``` - **访问对象**: 使用 `lock()` 方法获取一个临时的 `shared_ptr`,若原对象已被释放,则返回空指针: ```cpp if (auto temp = weak.lock()) { std::cout << *temp << std::endl; // 安全访问 } else { std::cout << "对象已释放" << std::endl; } ``` #### 2. 如何解决循环引用问题? 循环引用是指两个或多个对象通过 `shared_ptr` 互相持有对方,导致引用计数无法归零,内存无法释放。 **示例场景**: ```cpp class B; class A { public: std::shared_ptr<B> b_ptr; }; class B { public: std::shared_ptr<A> a_ptr; }; auto a = std::make_shared<A>(); auto b = std::make_shared<B>(); a->b_ptr = b; b->a_ptr = a; // 循环引用,a 和 b 的引用计数均为 2,无法释放 ``` **解决方法**: 将其中一个 `shared_ptr` 替换为 `weak_ptr`,打破循环: ```cpp class B; class A { public: std::shared_ptr<B> b_ptr; }; class B { public: std::weak_ptr<A> a_ptr; // 改为 weak_ptr }; auto a = std::make_shared<A>(); auto b = std::make_shared<B>(); a->b_ptr = b; b->a_ptr = a; // a 的引用计数保持为 1,b 的引用计数为 2 ``` 当外部 `a` 释放时,其引用计数归零,`A` 对象被销毁,随后 `B` 对象引用计数减为 1,最终释放[^3][^4]。 #### 3. 注意事项 - **生命周期管理**:`weak_ptr` 不拥有对象,需通过 `lock()` 检查对象有效性。 - **线程安全**:`lock()` 在多线程环境中需配合同步机制使用。 - **性能开销**:`weak_ptr` 的 `lock()` 操作涉及原子操作,但通常可忽略不计[^5]。 #### 4. 适用场景 - **观察者模式**:观察者持有被观察者的 `weak_ptr`,避免影响被观察者的生命周期。 - **缓存系统**:缓存项使用 `weak_ptr`,当主对象释放时缓存自动失效。 - **解决循环引用**:如树形结构、双向链表等[^2][^4]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值