智能指针(三) weak_ptr
智能指针(三) weak_ptrweak_ptr的初始化和赋值看名字就知道他是一个弱引用他的存在是为了辅助shared_ptr的循环引用问题它不占用引用数。大家理解时将weak_ptr看成用来监视shared_ptr强引用的生命周期用。是一种对shared_ptr的扩充。void func() { // weak_ptr的创建 // weak_ptrint wi (new int); //error 只能通过shared_ptr或者weak_ptr构造赋值。 // 1 weak_ptr初始化赋值 std::shared_ptrint sh std::make_sharedint(); // 默认值为0 cout sh.use_count() endl; // 1 std::weak_ptrint w(sh); // 用shared_ptr构造 std::weak_ptrint w1(w); // 用weak_ptr构造 cout sh.use_count() endl; // 1 // weak_ptr 的构造和析构不会改变 shared_ptr的引用计数强引用计数 std::weak_ptrint w2 sh; // 用shared_ptr赋值 std::weak_ptrint w3 w2; // 用weak_ptr赋值 cout sh.use_count() endl; // 1 //weak_ptr 的构造和析构不会改变 shared_ptr的引用计数强引用计数 // 2 错误写法 weak_ptrint wi(shared_ptrint()); // 使用匿名对象创建 weak_ptr ,报错wi是一个函数不是一个对象 // 这个语法是声明函数 // 然后shared_ptr的默认构造是nullptr // make_shared默认调用T的构造函数 , 就是返回一个指向0的非空指针 weak_ptrint wi shared_ptrint(); // 匿名对象初始化 // weak_ptrint wi(make_sharedint()); //这样是可行的 匿名对象初始化 };lock 函数介绍它没有重载 * 和 - 运算符而且weak_ptr 指向的对象可能会释放不受weak_ptr控制,我们不能操作一个已经释放的对象因此不可以直接通过 weak_ptr 访问对象 典型的用法是通过 lock() 成员函数来获得 shared_ptr进而使用对象。Iock()功能就是查看weak _ptr所指向的对象是否存在,如果存在,那么这个1ock他就返回一个指向该对象的shared_ptr,(这也会导致原来的shared_ptr指向对象的引用计数加一); 如果不存在就返回一个指向nullptr的shared_ptrvoidfunc(){weak_ptrintwishared_ptrint();// 匿名对象初始化// weak_ptrint wi(make_sharedint()); //这样是可行的 匿名对象初始化if(nullptrwi.lock()){coutwi指向的对象已经被销毁没有返回shared_ptrendl;}else{coutwi 正指向一个对象endl;}}voidfunc2(){autosimake_sharedint(100);//coutsi.use_count si.use_count()endl;//1weak_ptrintwi(si);coutsi.use_count si.use_count()endl;//1autoretwi.lock();//2if(nullptrret){coutwi指向的对象已经被销毁没有返回shared_ptrendl;}elseif(si.use_count()2){coutsi 指向的对象的引用计数 加一endl;}else{coutother caseendl;}coutsi.use_count si.use_count()endl;}}use_cout()weak_ptr的use_Count也只能计算weak_ptr指向对象的强引用计数voidfunc(){autosimake_sharedint(100);autosi2(si);coutsi.use_count si.use_count()endl;weak_ptrintwisi;// 此时只有一个软引用计数coutwi.use_count wi.use_count()endl;}expired() 和 reset()expired():是否过期的意思。弱该指针的use_count0为0表示该弱指针所指向的对象已经不存在了用之前需要使用expired函数来检测是否过期然后使用lock函数来获取其对应的shared_ptr对象然后进行后续操作reset():将该弱引用指针设置为空不影响指向该对象的强引用数量但指向该对象的弱引用数量会减少1,classCB;classCA{public:CA(){coutCA() called! endl;}voidshow(){coutthis is class CA!endl;}private:shared_ptrCBm_ptr_b;};classCB{public:CB(){coutCB() called! endl;}voidshow(){coutthis is class CB!endl;}private:shared_ptrCAm_ptr_a;};voidtest2(){shared_ptrCAptr_a(newCA());// 输出CA() called!shared_ptrCBptr_b(newCB());// 输出CB() called!coutptr_a use count : ptr_a.use_count()endl;// 输出ptr_a use count : 1coutptr_b use count : ptr_b.use_count()endl;// 输出ptr_b use count : 1weak_ptrCAwk_ptr_aptr_a;weak_ptrCBwk_ptr_bptr_b;if(!wk_ptr_a.expired()){wk_ptr_a.lock()-show();// 输出this is class CA!}if(!wk_ptr_b.expired()){wk_ptr_b.lock()-show();// 输出this is class CB!}// 编译错误// 编译必须作用于相同的指针类型之间// wk_ptr_a.swap(wk_ptr_b); // 调用交换函数wk_ptr_b.reset();// 将wk_ptr_b的指向清空if(wk_ptr_b.expired()){coutwk_ptr_b is invalidendl;// 输出wk_ptr_b is invalid 说明改指针已经无效}wk_ptr_bptr_b;if(!wk_ptr_b.expired()){wk_ptr_b.lock()-show();// 输出this is class CB! 调用赋值操作后wk_ptr_b恢复有效}// 编译错误// 编译必须作用于相同的指针类型之间// wk_ptr_b wk_ptr_a;// 最后输出的引用计数还是1说明之前使用weak_ptr类型赋值不会影响引用计数coutptr_a use count : ptr_a.use_count()endl;// 输出ptr_a use count : 1coutptr_b use count : ptr_b.use_count()endl;// 输出ptr_b use count : 1}lock();和 expired();的区别lock() 理解创建新的 std::shared_ptr 对象它共享被管理对象的所有权。若无被管理对象即 *this 为空则返回亦为空的 shared_ptr 。 等效地返回 expired() ? shared_ptr() : shared_ptr(*this) 原子地执行。线程安全方面classFoo;autopimake_sharedFoo();weak_ptrFoowpPtrpi;// 使用spFoo 指针代码段一// 使用 lock();shared_ptrFoospFoowpPtr.lock();// spFoo 是 lock()if(spFoo)// 如果 spFoo 不为空说明 spFoo-DoSomething();是合法的即访问非空指针的内存是合理的{spFoo-DoSomething();// 操作该指针(强引用)}// 使用expired()功能// 使用spFoo 指针代码段二if(!wpPtr.expired())// 如果没有过期 ,指向的对象没有被销毁{shared_ptrFoospFoowpPtr.lock();// 获得指向该对象的shared_ptrspFoo-DoSomething();// 操作该强引用}上述哪种方法更好这两种方式有什么不同先看下面的两个使用spFoo 例子(多线程下)if(!wpPtr.expired()){// --- hereshared_ptrFoospFoowpPtr.lock();spFoo-DoSomething();}在--- here我们知道在多线程环境没有有关wpPtr状态。它可能已过期或未过期(当两个线程操作一个指针对象且这个对象的引用计数是1均进入到here处时 如果一个线程销毁了wpPtr 引用计数为0此时访问指针对象是非法的)。在另一方面if(wpPtr.expired()){// --- there}在--- there我们做知道弱指针已过期。是线程安全的(尽管多个线程 能进入到 there ,但 也是在wpPtn 为空的前提下不会操作指针对象)结论可见 使用spFoo 指针代码段二 是线程不安全的另一种首选技术是提前退出autospFoowpPtr.lock();if(!spFoo)returnerror(wp empty);spFoo-DoSomething();