中国室内设计网站有哪些,网站开发运营产品经理招聘,程序员网站开发框架,网站建设辶金手指排名十一文章目录 1. shared_ptr 存在的问题2. 使用weak_ptr2.1 初始化 weak_ptr2.2 访问数据 3. 附录4. 参考文献 1. shared_ptr 存在的问题
与 shared_ptr 的引入要解决普通指针存在的一些问题一样#xff0c;weak_ptr 的引入#xff0c;也是因为 shared_ptr 本身在某些情况下weak_ptr 的引入也是因为 shared_ptr 本身在某些情况下存在一些问题或有一些不完善的地方考虑以下两个场景
循环引用(cyclic references)。如果两个对象使用 shared_ptrs 互相引用那么就算将两个对象指针设为nullptr此时理应释放资源但由于内部的循环引用此时 shared_ptrs 的 use_count() 1导致并不会释放资源 下面为循环引用的一个具体示例代码
#include iostream
#include string
#include vector
#include memory
using namespace std;
class Person {
public:
string name;
shared_ptrPerson mother;
shared_ptrPerson father;
vectorshared_ptrPerson kids;
Person (const string n,
shared_ptrPerson m nullptr,
shared_ptrPerson f nullptr)
: name(n), mother(m), father(f) {
}
~Person() {
cout delete name endl;
}
};
shared_ptrPerson initFamily (const string name)
{
shared_ptrPerson mom(new Person(name’s mom));
shared_ptrPerson dad(new Person(name’s dad));
shared_ptrPerson kid(new Person(name,mom,dad));
mom-kids.push_back(kid);
dad-kids.push_back(kid);
return kid;
}
int main()
{
shared_ptrPerson p initFamily(nico);
cout nico’s family exists endl;
cout - nico is shared p.use_count() times endl;
cout - name of 1st kid of nico’s mom: p-mother-kids[0]-name endl;
p initFamily(jim);
cout jim’s family exists endl;
}首先initFamily() 创建了三个Person对象mondad 和 kid。kid 使用了 mom 和 dad 的共享指针进行创建。mom 和 dad 也将 kid 共享指针插入到 vector 中最后将 kid 指针返回给 pinitFamily() 调用完结果如下图所示。 kid 有指向 mom 和 dad 的指针mom 和 dad 中也有指向 kid 的指针此时循环引用就产生了。因此这里 p 的 use_count3所以当赋值一个新的Person给p或者让p为nullptr或者在 main() 末尾离开了 p 的作用域 —— 没有 Person 对象会被释放因为每个至少有一个指针指向因此输出 delete name 永远不会调用实际输出如下
nico’s family exists
- nico shared 3 times
- name of 1st kid of nicos mom: nico
jim’s family exists如果只是想共享而不是想拥有对象。即一个指针的生命周期要长于指向对象的生命周期。此时使用 shared_ptrs 会导致无法释放资源使用普通指针存在访问释放资源的风险后续对weak_ptr使用的讲解中进一步说明。 2. 使用weak_ptr
鉴于上面 shared_ptr 存在的问题C11 提供了 weak_ptr 类允许共享对象但并不实际拥有对象这个类需要传入一个共享指针来创建。当最后一个共享指针失去对象所有权(要释放空间与资源了)共享对象的 weak_ptr 自动设为空(本来就没有对象的所有权自然也不负责对于空间与资源的释放) 。
我们使用 weak_ptr 改写上面的代码
class Person {
public:
string name;
shared_ptrPerson mother;
shared_ptrPerson father;
vectorweak_ptrPerson kids; // weak pointer !!!
Person (const string n,
shared_ptrPerson m nullptr,
shared_ptrPerson f nullptr)
: name(n), mother(m), father(f) {
}
~Person() {
cout delete name endl;
}
};通过使用 weak_ptr 打破共享指针的循环引用只有 kid 指向父母的指针使用共享指针父母指向 kid 的指针使用(下图中的虚线) 这样 p 的 use_coun1所以 p 删除时会释放对应的内存和资源。程序输出如下
nico’s family exists
- nico shared 1 times
- name of 1st kid of nicos mom: nico
delete nico
delete nico’s dad
delete nico’s mom
jim’s family exists
delete jim
delete jim’s dad
delete jim’s mom下面详细讲解 weak_ptr 的使用
2.1 初始化 weak_ptr
因为 weak_ptr 只能使用 shared_ptr 初始化所以 weak_ptr 只提供了默认构造函数、拷贝构造函数以及传入 shared_ptr 的构造函数因为不是显式构造函数所以可以在 vector 中直接插入共享指针(隐式转换)
mom-kids.push_back(kid);
dad-kids.push_back(kid);2.2 访问数据
之前使用 shared_ptr 访问 vector 中共享指针指向的数据使用以下语法
p-mother-kids[0]-name而对于 weak_ptr 则要使用如下语法
p-mother-kids[0].lock()-namelock() 获取共享指针。如果在 lock 获取共享指针时资源已经被释放了则返回空的 shared_ptr。
此时再调用操作符 * 或 - 都会产生未定义行为。
因此最好在获取共享指针前首先对资源是否释放进行检查有如下 3 种方法
调用 expired() 方法如果 weak_ptr 不再共享一个对象则返回 true。这与检查 use_count() 是否等于 0 是等价的但可能运行速度更快。可以显式将 weak_ptr 使用对应构造函数转换为 shared_ptr。如果此时没有合法的引用对象则这个构造函数抛出一个 bad_weak_ptr 异常。 这是一个派生自 std::exception 的一个异常what() 返回 bad_weak_ptr (每个设备上实现有所差异)。可以调用 use_count() 查询关联对象所有者的数量。如果返回值是 0这将不会再有合法对象。这个方法最好只是在debug时使用因为效率不高。
三种方法的具体代码如下
try {
shared_ptrstring sp(new string(hi)); // create shared pointer
weak_ptrstring wp sp; // create weak pointer out of it
sp.reset(); // release object of shared pointer
cout wp.use_count() endl; // prints: 0
cout boolalpha wp.expired() endl; // prints: true
shared_ptrstring p(wp); // throws std::bad_weak_ptr
}
catch (const std::exception e) {
cerr exception: e.what() endl; // prints: bad_weak_ptr
}3. 附录
A. weak_ptr 操作列表 4. 参考文献
《The C Standard Library》A Tutorial and Reference, Second Edition, Nicolai M. Josuttis.