头文件:
模版类:template
声明方式:std::weak_ptr
根据boost库的官方描述,weak_ptr是由shared_ptr管理的一种弱引用对象的模版类。weak_ptr
的对象能够使用shared_ptr
指针的构造函数转换为一个shared_ptr对象。但是这里shared_ptr
的构造函数参数需要包含weak_ptr
的lock成员,该成员是weak_ptr用来获取shared_ptr的指针。
这样当shared_ptr在多线程过程中被销毁时shared_ptr::reset
,weak_ptr的lock成员仍然能够保留shared_ptr的成员,直到当前shared_ptr正常终止,否则会出现非常危险的内存泄漏。关于lock()成员的作用如下描述:
如下代码
shared_ptr<int> p(new int(5));
weak_ptr<int> q(p);// some time laterif(int * r = q.get())
{ // use *r
}
多线程环境中shared_ptr是可以被多个线程共享,在r被使用之前p对象执行了p.reset()
,正如我们上一篇文章中对shared_ptr的描述(C++智能指针:shared_ptr 实现详解),reset成员会重置当前shared_ptr指针的指向。此时,当前线程如果继续使用r指针,势必会产生访问空地址的异常问题
根据以上问题,使用weak_ptr::lock()
成员来解决该问题
shared_ptr<int> p(new int(5));
weak_ptr<int> q(p);// some time later//使用weak_ptr的lock成员来获取shared_ptr的指针
if(shared_ptr<int> r = q.lock())
{ // use *r
}
关于lock()成员简单说明一下,lock成员获取到的shared_ptr p指针创建一个临时对象(我们weak_ptr弱引用的体现),这个临时对象同样指向p,即使p执了reset这样的delete引用的操作,弱引用对象仍然持有改智能指针的地址,直到r指针的生命周期结束才会释放。不得不佩服C++语言设计者的脑洞,为了保持C++对内存操作的自由,即使耗费再大的精力也要实现这一目标,工匠精神才让今天的C++越来越被底层程序员喜欢。
源码文件/boost/smart_ptr/weak_ptr.hpp
template<class T> class weak_ptr
{
private:// Borland 5.5.1 specific workaroundstypedef weak_ptr<T> this_type;
constructor
构造函数//默认构造函数
weak_ptr() BOOST_NOEXCEPT : px(0), pn() // never throws in 1.30+
{
}//拷贝构造函数
weak_ptr( weak_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn )
{
}
destructor
析构函数,这里weak_ptr使用的是默认析构函数,一般使用expired
返回空对象或者user_count()为0的情况则辅助shared_ptr释放引用operator=
1. weak_ptr & operator=( weak_ptr && r ) BOOST_NOEXCEPT
{ this_type( static_cast< weak_ptr && >( r ) ).swap( *this );return *this;
}//2.这里会更加安全,使用lock成员获取Y类型的指针
template<class Y>
weak_ptr & operator=( weak_ptr<Y> const & r ) BOOST_NOEXCEPT
{ boost::detail::sp_assert_convertible< Y, T >();px = r.lock().get();pn = r.pn;return *this;
}3.
template<class Y>
weak_ptr & operator=( shared_ptr<Y> const & r ) BOOST_NOEXCEPT
{ boost::detail::sp_assert_convertible< Y, T >();px = r.px;pn = r.pn;return *this;
}
weak_ptr::swap
成员,交换两个weak_ptr所指内容以及地址 void swap(this_type & other) BOOST_NOEXCEPT
{ //先交换地址,再交换内容std::swap(px, other.px);pn.swap(other.pn);
}
weak_ptr::reset
成员,·重新指定对象地址和内容,就像是重新使用默认构造函数进行了初始化void reset() BOOST_NOEXCEPT // never throws in 1.30+
{ //使用默认构造函数构造的对象和当前对象进行swap操作this_type().swap(*this);
}
weak_ptr::use_count
成员,获取shared_ptr对象被引用的次数。如果为空,则返回0long use_count() const BOOST_NOEXCEPT
{ return pn.use_count();
}
weak_ptr::expired
成员,当根据use_count==0来返回bool,其返回为true的时候,使用lock获取weak_ptr的指针只能获取到空指针 bool expired() const BOOST_NOEXCEPT
{ return pn.use_count() == 0;
}
weak_ptr::lock
成员,会向weak_ptr对象返回一个shared_ptr。正如我们之前在weak_ptr作用中所描述的,防止多线程访问时的shared_ptr内存泄漏。此时weak_ptr对象获取到的指针为临时指针,会指向shared_ptr对象之前所指向的地址。shared_ptr<T> lock() const BOOST_NOEXCEPT
{ return shared_ptr<T>( *this, boost::detail::sp_nothrow_tag() );
}
#include
#include struct C { int* data;};int main () { std::shared_ptr<int> sp (new int);std::weak_ptr<int> wp1;std::weak_ptr<int> wp2 (wp1);std::weak_ptr<int> wp3 (sp);std::cout << "use_count:
";//weak_ptr对象如果为经shared_ptr初始化,//它是没有引用计数的,所以这里wp1和wp2引用计数都为0//只有wp3经过了shared_ptr初始化,它的引用计数才为1std::cout << "wp1: " << wp1.use_count() << '
';std::cout << "wp2: " << wp2.use_count() << '
';std::cout << "wp3: " << wp3.use_count() << '
';return 0;
}
输出如下:use_count:
wp1: 0
wp2: 0
wp3: 1
weak_ptr::operator=
赋值运算符// weak_ptr::operator= example
#include
#include int main () { std::shared_ptr<int> sp1,sp2;std::weak_ptr<int> wp;// sharing group:// --------------sp1 = std::make_shared<int> (10); // sp1wp = sp1; // sp1, wpsp2 = wp.lock(); // sp1, wp, sp2sp1.reset(); // wp, sp2//通过lock保留的临时指针,重新获取到了shared_ptr共享的地址sp1 = wp.lock(); // sp1, wp, sp2std::cout << "*sp1: " << *sp1 << '
';std::cout << "*sp2: " << *sp2 << '
';return 0;
}
输出如下*sp1: 10
*sp2: 10
std::weak_ptr::swap
交换指针地址以及对应的内容#include
#include int main () { std::shared_ptr<int> sp1 (new int(10));std::shared_ptr<int> sp2 (new int(20));std::weak_ptr<int> wp1(sp1);std::weak_ptr<int> wp2(sp2);std::cout << "wp1 -> " << *wp1.lock() << " " << wp1.lock() << '
';std::cout << "wp2 -> " << *wp2.lock() << " " << wp2.lock() << '
';//这里的swap仅仅是交换wp2的各自的指向地址//并不会直接导致对应智能指针原始指针的地址交换//根据输出,所以很明显,交换完成之后weak_ptr对象指向发生了变化,但是并未导致share_ptr指针的指向变化wp1.swap(wp2);std::cout << "sp1 -> " << *sp1 << " " << sp1 << '
';std::cout << "sp2 -> " << *sp2 << " " << sp2 << '
';std::cout << "wp1 -> " << *wp1.lock() << " " << wp1.lock() << '
';std::cout << "wp2 -> " << *wp2.lock() << " " << wp2.lock() << '
';return 0;
}
输出如下:wp1 -> 10 0x11daf90
wp2 -> 20 0x11dafd0
sp1 -> 10 0x11daf90
sp2 -> 20 0x11dafd0
wp1 -> 20 0x11dafd0
wp2 -> 10 0x11daf90
std::weak_ptr::reset
成员,执行之后weak_ptr对象就像是重新执行了默认构造函数,又变成了一个空的对象// weak_ptr::reset example
#include
#include int main () { std::shared_ptr<int> sp (new int(10));std::weak_ptr<int> wp(sp);std::cout << "1. wp " << (wp.expired()?"is":"is not") << " expired
";std::cout << "4. wp " << wp.use_count() << " *wp " << *wp.lock() << '
';wp.reset();std::cout << "2. wp " << (wp.expired()?"is":"is not") << " expired
";std::cout << "3. sp " << sp.use_count() << " *sp " << *sp << '
';return 0;
}
输出如下1. wp is not expired
2. wp 2 *wp 10
3. wp is expired
4. sp 1 *sp 10
shared_ptr和weak_ptr主要区别如下
参考文档:
http://www.cplusplus.com/reference/memory/weak_ptr/
https://www.boost.org/doc/libs/1_66_0/libs/smart_ptr/doc/html/smart_ptr.html#weak_ptr
C++11标准中可以为模板定义别名,比如
template
先说结论,智能指针都是非线程安全的。
多线程调度智能指针
这里案例使用的是shared_ptr,其他的unique_ptr或者weak_ptr的结果都是类似的,如下多线程调度代码:
#include
文章目录unique_ptr 智能指针的实现shared_ptr 智能指针的实现指针类型转换
unique_ptr 智能指针的实现
一个对象只能被单个unique_ptr 所拥有。
#include
文章目录shared_ptr描述声明作用原理实现函数使用关于shared_ptr循环引用问题
shared_ptr描述
声明
shared_ptr属于C++11特性中新加的一种智能指针,它的实现方式是模版类,头文件
enable_shared_from_this解析 enable_shared_from_this,是一个以其派生类为模板类型实参的基础模板,继承它,this指针就能变成shared_ptr。 什么时候该使用enable_shared_from_this模板类 在看下面的例子之前,简单说下使用背景,单有...