一、weak_ptr简介
weak_ptr 辅助 shared_ptr 进行工作;
强指的就是 shared_ptr,弱指的就是 weak_ptr。
weak_ptr:也是个类模板,也是个智能指针,这个智能指针指向一个由 shared_ptr 管理的对象,但是 weak_ptr 这种指针不控制所指向对象的生命周期。
换句话来说,将 weak_ptr 绑定到 shared_ptr 上并不会改变 shared_ptr 的引用计数(更确切的说,weak_ptr 的构造和析构不会增加或减少所指向对象的引用计数)。
当 shared_ptr 需要释放所指定的时候照常释放,不管是否有 weak_ptr 指向该对象。
weak 这个意思 “弱” 能力弱(若共享/弱引用;共享其他的 shared_ptr 所指向的对象);控制不了所指向对象的生命周期。
这个弱引用( weak_ptr )的作用:大家可以理解成监视 shared_ptr (强引用)的生命周期用,是一种对 shared_ptr 能力的扩充。
weak_ptr 不是一种独立的智能指针,不能用来操作所指向的资源,所以它看起来像是一个shared_ptr 的助手。(旁观者)
weak_ptr 能够监视到它所指向的对象是否存在;
<1>weak_ptr创建
我们创建 weak_ptr 的时候,一般是用一个 shared_ptr 来初始化;
int main()
{
auto pi = make_shared<int>(100); //shared_ptr
weak_ptr<int> piw(pi); // piw弱共享pi,pi引用计数(强引用计数不会改变)不会改变,
// 但是弱引用计数会改变(弱引用计数会从0变为1);
return 0;
}
强引用计数才能决定对象的生存期,弱引用计数对对象生存期没有影响
int main()
{
auto pi = make_shared<int>(100); //shared_ptr
weak_ptr<int> piw;
piw = pi; //pi是一个shared_ptr,赋值给一个weak_ptr,两者指向同一个内存对象;
weak_ptr<int> piw2;
piw2 = piw; //把weak_ptr赋给另外一个weak_ptr,现在pi是一个强引用,piw和piw2是两个弱引用;
weak_ptr<int> piw2(piw);
return 0;
}
lock():功能就是检查weak_ptr所指向的对象是否存在,如果存在,那么这个lock他就能够返回一个指向该对象的shared_ptr
(指向对象的强引用计数加一)
如果所指向的对象不存在,lock返回一个空的shared_ptr
int main()
{
auto pi = make_shared<int>(100); //shared_ptr
weak_ptr<int> piw;
piw = pi; //pi是一个shared_ptr,赋值给一个weak_ptr,两者指向同一个内存对象;
weak_ptr<int> piw2;
piw2 = piw; //把weak_ptr赋给另外一个weak_ptr,现在pi是一个强引用,piw和piw2是两个弱引用;
weak_ptr<int> piw2(piw);
pi.reset(); // 因为pi是唯一指向该对象的强引用智能指针,所以reset()会释放pi所指向的对象,同时将pi置空
auto pi2 = piw.lock(); //pi2是一个shared_ptr
if (pi2 != nullptr) //也可以写成if(pi2)
{
//所指向的对象存在
*pi2 = 12;
}
else
{
cout << "很遗憾,lock()失败" << endl;
}
return 0;
}
总结上面这段代码:weak_ptr 能够判断所指向的对象是否存在,这种能力。
二:weak_ptr常用操作
<1>use_count
获取与该弱指针所共享对象的其他 shared_ptr 的数量,或者说获得当前所观测资源的强引用计数;
int main()
{
auto pi = make_shared<int>(100);
auto pi2(pi); //是一个shared_ptr;
weak_ptr<int> piw(pi);
auto piw2(piw);
int isc = piw.use_count();
cout << isc << endl;
return 0;
}
<2>expired()
是否过期的意思,弱指针的 use_count() 返回0表示该弱指针所指向的对象已经不存在了,则返回true,否则返回false。
换句话说,这个函数用来判断所观测的资源是否被释放
int main()
{
auto pi = make_shared<int>(100);
auto pi2(pi); //是一个shared_ptr;
weak_ptr<int> piw(pi);
auto piw2(piw);
pi.reset();
pi2.reset();
if (piw.expired())
{
cout << "对象已经过期" << endl;
}
return 0;
}
<3>reset()
将该弱指针置为空,不会影响指向该对象的强引用数量,但指向该对象的弱引用数量会减少1。
piw.reset();
<4>lock()
int main()
{
auto pi = make_shared<int>(100);
auto pi2(pi); //是一个shared_ptr;
weak_ptr<int> piw(pi);
auto piw2(piw);
pi.reset();
pi2.reset();
weak_ptr<int> ptw;
{
auto p1 = make_shared<int>(100);
ptw = p1; //可以用shared_ptr给weak_ptr赋值
}
//ptw就会过期;
if (!ptw.expired())
{
auto p2 = ptw.lock(); //返回一个shared_ptr, 并且此时强引用计数为2;
if (p2 != nullptr)
{
//做一些操作
int test;
test = 1;
//离开这个范围,强引用计数,会恢复为1
}
}
else
{
//已经过期
int test;
test = 1;
}
return 0;
}
走到这里,则强引用计数变回了1;
三:尺寸问题
weak_ptr pw;
weak_ptr和shared_ptr一样大,裸指针的2倍
int* p;
int ilen1 = sizeof§; //4个字节,是个裸指针
int ilen2 = sizeof(pw); //8个字节,两个裸指针
auto pi = make_shared(100); //后续还会继续讲解shared_ptr
weak_ptr piw(pi);
第一个裸指针指向的是这个智能指针所指向的对象;
第二个裸指针指向一个很大的数据结构(控制块),这个控制块里有:
1.所指对象的强引用计数
2.所指对象的弱引用计数
3.其他数据,比如自定义删除器的指针等等
总结: 基本具备能够读懂实战代码的能力。大家缺乏实战。