网站建设夹夹虫公司,网站开发 公司简介,租车网站系统规划,商务网站建设的主流程weak_ptr
weak_ptr是为配合shared_ptr而引入的一种智能指针#xff0c;它更像是shared_ptr的一个助手而不是智能指针#xff0c;因为它不具有普通指针的行为#xff0c;没有重载 operator*和-。它的最大作用在于协助shared_ptr工作#xff0c;像旁观者那样观测资源的使…weak_ptr
weak_ptr是为配合shared_ptr而引入的一种智能指针它更像是shared_ptr的一个助手而不是智能指针因为它不具有普通指针的行为没有重载 operator*和-。它的最大作用在于协助shared_ptr工作像旁观者那样观测资源的使用情况。
类摘要
templateclass T
class weak_ptr
{
public:weak_ptr(); //构造函数templateclass Y weak_ptr(shared_ptrY const r);weak_ptr(weak_ptr const r);~weak_ptr(); //析构函数weak_ptr operator (weak_ptr const r); //赋值long use_count() const; //引用计数bool expired() const; //是否失效指针shared_ptrT lock() const; //获取shared_ptrvoid reset(); //重置指针void swap(weak_ptrT b); //交换指针
};weak_ptr的接口很小正如它的名字是一个“弱”指针但它能够完成一些特殊的工作足以证明它的存在价值。
用法
weak_ptr被设计为与shared_ptr协同工作可以从一个shared_ptr或者另一个weak_ptr对象构造获得资源的观测权。但weak_ptr没有共享资源它的构造不会引起指针引用计数的增加。同样weak_ptr析构时也不会导致引用计数减少它只是一个静静的观察者。
使用weak_ptr的成员函数 use_count()可以观测资源的引用计数另一个成员函数expired()的功能等价于use_count()0但更快表示被观测的资源也就是被shared_ptr管理的资源已经不复存在。
weak_ptr没有重载operator*和-这是特意的因为它不共享指针不能操作资源这正是它“弱”的原因。但它可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象把弱关系转换为强关系从而操作资源。但当expired()true的时候lock()函数将返回一个存储空指针的shared_ptr。
shared_ptrint sp(new int(10)); //一个shared_ptr
assert(sp.use_count() 1);weak_ptrint wp(sp); //从shared_ptr创建weak_ptr
assert(wp.use_count() 1); //weak_ptr不影响引用计数if (!wp.expired()) //判断weak_ptr观察的对象是否失效
{shared_ptrint sp2 wp.lock(); //获得一个shared_ptr*sp2 100;assert(wp.use_count() 2); //退出作用域,sp2自动析构,引用计数减1
}assert(wp.use_count() 1);
sp.reset(); //shared_ptr失效
assert(wp.expired());
assert(!wp.lock()); //weak_ptr将获得一个空指针enable_shared_from_this
weak_ptr的一个重要用途是获得this 指针的 shared_ptr使对象自己能够生产shared_ptr管理自己对象使用weak_ptr观测this指针这并不影响引用计数在需要的时候就调用lock()函数返回一个符合要求的shared_ptr供外界使用。
这个解决方案被实现为一个惯用法在头文件boost/enable_shared_from_this.hpp定义了一个助手类enable_shared_from_thisT它的声明摘要如下
templateclass T
class enable_shared_from_this //辅助类需要继承使用
public:shared_ptrT shared_from_this(); //工厂函数产生this的shared_ptr使用的时候只需要让想被shared_ptr管理的类从它派生即可成员函数shared_from_this()会返回this的shared_ptr。例如
class self_shared: //一个需要用shared_ptr自我管理的类public enable_shared_from_thisself_shared
{
public:self_shared(int n) : x(n){}int x;void print(){ cout self_shared : x endl; }
};int main()
{auto sp make_sharedself_shared(313);sp-print();auto p sp-shared_from_this();p-x 1000;p-print();
}需要注意的是千万不能对一个普通对象非shared_ptr管理的对象使用shared_from_this()获取shared_ptr例如
self_shared ss;
auto p ss.shared_from_this(); //错误这样虽然语法上正确编译也无问题但在运行时会导致shared ptr析构时企图删除一个栈上分配的对象发生未定义行为。
enable_shared_from_raw
smart_ptr库在未文档化的头文件boost/smart_ptr/enable_shared_from_raw .hpp里提供另外一个与 enable_shared_from_this类似的辅助类enable_shared_from_raw它不要求对象必须被一个shared_ptr管理可以直接从一个原始指针创建出shared_ptr。
enable_shared_from_raw的类摘要如下
class enable_shared_from_raw
{
protected:enable_shared_from_raw();enable_shared_from_raw(enable_shared_from_raw const );enable_shared_from_raw operator(enable_shared_from_raw const );~enable_shared_from_raw()
private :templateclass Y friend class shared_ptr;templatetypenameTfriend boost::shared_ptrT shared_from_raw(T *);templatetypename Tfriend boost::weak_ptrT weak_from_raw(T *);
};enable_shared_from_raw利用了shared_ptr的别名构造函数特性内部持有一个void*的空指针shared_ptr作为引用计数的观察者从而达到管理原始指针的目的。
enable_shared_from_raw同样需要继承使用但它不是模板类所以不需要指定模板参数比 enable_shared_from_this写法上要简单一些。它不提供成员函数shared_from_this()而是用两个friend函数shared_from_raw()和weak_from_raw()完成创建智能指针的工作。
但请注意在调用shared_from_raw()后由于存在shared_ptr成员变量的原因对象内部会有一个shared_ptr的强引用所以即使其他的 shared_ptr都析构了原始指针也不会被自动删除因为use_count() 1——这使得enable_shared_from_raw用法略微不同于enable_shared_from_this它可以安全地从一个普通对象而非指针创建出shared_ptr。
示范enable_shared_from_raw用法的代码如下
#include boost/smart_ptr/enable_shared_from_raw.hppclass raw_shared :public boost::enable_shared_from_raw
{
public:raw_shared(){std::cout raw_shared ctor std::endl;}~raw_shared(){std::cout raw_shared dtor std::endl;}
};int main()
{raw_shared x; //一个普通对象assert(weak_from_raw(x).use_count() 1); //此时无引用,注意要用取地址auto px shared_from_raw(x); //获取shared_ptrassert(px.use_count() 2); //引用计数为2!
} //对象自动删除把enable_shared_from_raw应用于原始指针要当心使用不当有可能造成内存泄漏
int main()
{auto p new raw_shared; //创建一个原始指针auto wp weak_from_raw(p); //获取weak_ptrassert(wp.use_count() ); //此时无引用auto sp shared_from_raw(p); //获取shared_ptrassert(sp.use_count() 2); //引用计数为2!auto sp2 sp; //拷贝一个shared_ptrauto wp2 weak_from_raw(p); //获取weak_ptrassert(wp2.use_count() 3); //引用计数为3
} //对象没有被删除,内存泄露!如果在代码里的某个时刻使用shared_ptr来管理原始指针——而不是调用shared_from_raw()那么指针的管理权就会转移到 shared_ptr从而可以正确地自动销毁例如
int main()
{auto p new raw_shared; //创建一个原始指针decltype(shared_from_raw(p)) spx(p); //使用shared_ptr管理指针... //其他操作
} //对象被自动删除enable_shared_from_raw的用法比较特殊实际应用的场景较少也许这就是它没有在 Boost库里被文档化的原因。
打破循环引用
有的时候代码中可能会出现“循环引用”这时shared_ptr的引用计数机制就会失效导致不能正确释放资源例如
#include boost/smart_ptr.hpp
using namespace boost;class node //一个用于链表节点的类
{
public:~node() //析构函数输出信息{std::cout deleted std::endl;}typedef shared_ptrnode ptr_type; //指针类型使用shared_ptrptr_type next; //后继指针
};int main()
{auto p1 make_sharednode(); //两个节点对象auto p2 make_sharednode();p1-next p2; //形成循环链表p2-next p1; assert(p1.use_count() 2); //每个shared_ptr的引用计数都是2assert(p2.use_count() 2);} //退出作用域,shared_ptr无法正确析构上面的代码中两个节点对象互相持有对方的引用每一个shared_ptr的引用计数都是2因此在析构时引用计数没有减至0不会调用删除操作导致内存泄漏。
这个时候我们就可以使用weak_ptr因为它不会增加智能指针的引用计数这样就把原来的强引用改变为弱引用在可能存在循环引用的地方打破了循环而在真正需要shared_ptr的时候调用weak_ptr的lock()函数
class node //一个用于链表节点的类
{
public:~node() //析构函数输出信息{std::cout deleted std::endl;}typedef weak_ptrnode ptr_type; //指针类型使用weak_ptrptr_type next; //后继指针
};int main()
{auto p1 make_sharednode(); //两个节点对象auto p2 make_sharednode();p1-next p2; //形成循环链表p2-next p1; //引用使用了weak_ptr所以正常assert(p1.use_count() 1); //每个shared_ptr的引用计数都是2assert(p2.use_count() 1); //没有了循环引用if (!p1-next.expired()) //检查弱引用是否有效{auto p3 p1-next.lock(); //调用lock()获得强引用}} //退出作用域,shared_ptr均正确析构代码示例
#include iostream
//using namespace std;#include boost/smart_ptr.hpp
using namespace boost;//void case1()
{shared_ptrint sp(new int(10));assert(sp.use_count() 1);weak_ptrint wp(sp);assert(wp.use_count() 1);assert(!wp.empty());if (!wp.expired()){shared_ptrint sp2 wp.lock();*sp2 100;assert(wp.use_count() 2);}assert(wp.use_count() 1);sp.reset();assert(wp.expired());assert(!wp.lock());
}//class self_shared :public enable_shared_from_thisself_shared
{
public:self_shared(int n) :x(n) {}int x;void print(){std::cout self_shared: x std::endl;}
};void case2()
{auto sp make_sharedself_shared(313);sp-print();auto p sp-shared_from_this();p-x 1000;p-print();
}//class node
{
public:~node(){std::cout deleted std::endl;}typedef weak_ptrnode ptr_type;//typedef shared_ptrnode ptr_type;ptr_type next;
};void case3()
{auto p1 make_sharednode();auto p2 make_sharednode();p1-next p2;p2-next p1;assert(p1.use_count() 1);assert(p2.use_count() 1);if (!p1-next.expired()){auto p3 p1-next.lock();}
}//
#include boost/smart_ptr/enable_shared_from_raw.hppclass raw_shared :public enable_shared_from_raw
{
public:raw_shared(){std::cout raw_shared ctor std::endl;}~raw_shared(){std::cout raw_shared dtor std::endl;}
};void case4()
{raw_shared x;assert(weak_from_raw(x).use_count() 1);auto px shared_from_raw(x);assert(px.use_count() 2);auto p new raw_shared;auto wp weak_from_raw(p);assert(wp.use_count() 1);decltype(shared_from_raw(p)) spx(p);auto sp shared_from_raw(p);//std::cout sp.use_count() std::endl;assert(sp.use_count() 2);//decltype(sp) spx(p);auto sp2 sp;auto wp2 weak_from_raw(p);assert(wp2.use_count() 3);
}//int main()
{case1();case2();case3();case4();
}