赞
踩
目录
weak_ptr 对象的构造有3种方法:
1,构造空对象,如 std::weak_ptr<CTest> weakPtr;
2,拷贝构造,如 std::weak_ptr<CTest> weakPtr2(weakPtr);
3,用shared_ptr 对象进行初始化,如
std::shared_ptr<CTest> ptr = std::make_shared<CTest>();
std::weak_ptr<CTest> weakPtr3(ptr);
- #include <stdio.h>
- #include <stdlib.h>
- #include <memory>
-
- class CTest
- {
- public:
- CTest(): mValue(100)
- {
- printf("constructor\n");
- }
-
- ~CTest()
- {
- printf("destructor\n");
- }
-
- int getValue()
- {
- return mValue;
- }
- private:
- int mValue;
- };
-
- int main()
- {
- std::weak_ptr<CTest> weakPtr;
- std::weak_ptr<CTest> weakPtr2(weakPtr);
- std::shared_ptr<CTest> ptr = std::make_shared<CTest>();
- std::weak_ptr<CTest> weakPtr3(ptr);
-
- int value = ptr->getValue();
- printf("value = %d, use_count = %d\n", value, ptr.use_count());
-
- value = (weakPtr3.lock())->getValue();
- printf("value = %d\n", value);
-
- ptr.reset();
- auto ptr2 = weakPtr3.lock();
- if(ptr2 == nullptr)
- {
- printf("weakPtr3.lock() = nullptr\n");
- return 0;
- }
- value = ptr2->getValue();
- return 0;
- }
bool expired() const noexcept; 函数返回 weak_ptr 对象是否是空的,或是它所属的所有者组中不再有shared_ptr。此函数与 use_count() == 0 意义相同。
- #include <stdio.h>
- #include <stdlib.h>
- #include <memory>
-
- class CTest
- {
- public:
- CTest(): mValue(100)
- {
- printf("constructor\n");
- }
-
- ~CTest()
- {
- printf("destructor\n");
- }
-
- int getValue()
- {
- return mValue;
- }
- private:
- int mValue;
- };
-
- int main()
- {
- std::weak_ptr<CTest> weakPtr;
- std::weak_ptr<CTest> weakPtr2(weakPtr);
- std::shared_ptr<CTest> ptr = std::make_shared<CTest>();
- std::weak_ptr<CTest> weakPtr3(ptr);
-
- if(weakPtr.expired())
- {
- printf("weakPtr is empty!\n");
- }
-
- if(weakPtr2.expired())
- {
- printf("weakPtr2 is empty!\n");
- }
-
- if(weakPtr3.expired())
- {
- printf("weakPtr3 is empty!\n");
- }
-
- return 0;
- }
我们可以看到源码是这样的:
shared_ptr<element_type> lock() const noexcept; 函数返回一个shared_ptr,其中包含weak_ptr对象在未过期时保留的信息。如果 weak_ptr 对象已过期(包括它是否为空),该函数将返回一个空的shared_ptr(就像默认构造的一样)。
- #include <stdio.h>
- #include <stdlib.h>
- #include <memory>
-
- class CTest
- {
- public:
- CTest(): mValue(100)
- {
- printf("constructor\n");
- }
-
- ~CTest()
- {
- printf("destructor\n");
- }
-
- int getValue()
- {
- return mValue;
- }
- private:
- int mValue;
- };
-
- int main()
- {
- std::weak_ptr<CTest> weakPtr;
- std::weak_ptr<CTest> weakPtr2(weakPtr);
- std::shared_ptr<CTest> ptr = std::make_shared<CTest>();
- std::weak_ptr<CTest> weakPtr3(ptr);
-
- std::shared_ptr<CTest> lck;
- lck = weakPtr.lock();
- if(lck == nullptr)
- {
- printf("weakPtr is empty!\n");
- }
-
- if(!weakPtr2.lock())
- {
- printf("weakPtr2 is empty!\n");
- }
-
- std::shared_ptr<CTest> test;
- if((test = weakPtr3.lock()) != nullptr)
- {
- printf("weakPtr3 is not empty! value = %d\n", test->getValue());
-
- }
-
- return 0;
- }
在使用 lock() 函数时,可以判断其是否为nullptr。当用 gdb 查看时可以看到:lck=weakPtr.lock()后,lck 就是 0。
我们可以看源码 lock() 函数是怎样实现的:
可以看到当对象过期时,构造了一个空的 shared_ptr<>对象进行返回,而这个空对象它的初始化值是这样的:
_M_ptr 是模板参数类型的指针,它指向的就是要管理的对象。而 _M_refcount 是管理引用计数的。所以一个空的 shared_ptr<> 并不管理任何对象,就不能当作对象指针来用了。但 use_count() 还是可以用的,用 lck.use_count() == 0 进行判断:
这里可能会有人疑问:lck 都是nullptr 了,怎么还能调用 use_count() 呢?这样调用不会崩溃吗?这个就要理解类与对象的关系了,可以参考 null 类对象。可以看源码:
weak_ptr 里有两个计数,一个是 _M_use_count 管理对象的引用计数,一个是 _M_weak_count 是不是用于它本身的析构用的,还没研究。weak_ptr 的基类:
- _Tp* _M_ptr; // Contained pointer.
- __weak_count<_Lp> _M_refcount; // Reference counter.
- template<_Lock_policy _Lp>
- class __weak_count
- {
- public:
- constexpr __weak_count() noexcept : _M_pi(0)
- { }
-
- __weak_count(const __shared_count<_Lp>& __r) noexcept
- : _M_pi(__r._M_pi)
- {
- if (_M_pi != 0)
- _M_pi->_M_weak_add_ref();
- }
__weak_count<_Lp> 模板类有一个成员 _M_pi, 其类型为 _Sp_counted_base<_Lp>* _M_pi;
_Sp_counted_base<_Lp> 就包含上述的两个计数。use_count() 函数调用的是_M_refcount._M_get_use_count();
1,解决shared_ptr 循环引用的问题。这个网上也有很多例子
2,在不延长shared_ptr 管理对象生命周期的情况下,探知这个对象是否已经无效。可以参考 muduo 的例子
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。