weak_ptr 智能指针的使用

目录

一,weak_ptr 变量的定义

二,expired() 成员函数

三,lock() 成员函数

四,use_count() 成员函数

五,为什么要用 weak_ptr


一,weak_ptr 变量的定义

weak_ptr 对象的构造有3种方法:

1,构造空对象,如 std::weak_ptr weakPtr;

2,拷贝构造,如 std::weak_ptr weakPtr2(weakPtr);

3,用shared_ptr 对象进行初始化,如

std::shared_ptr ptr = std::make_shared();

std::weak_ptr weakPtr3(ptr);

#include 
#include 
#include 

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 weakPtr;
    std::weak_ptr weakPtr2(weakPtr);
	std::shared_ptr ptr = std::make_shared();
    std::weak_ptr 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;
}

二,expired() 成员函数

bool expired() const noexcept; 函数返回 weak_ptr 对象是否是空的,或是它所属的所有者组中不再有shared_ptr。此函数与 use_count() == 0 意义相同。

#include 
#include 
#include 

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 weakPtr;
	std::weak_ptr weakPtr2(weakPtr);
	std::shared_ptr ptr = std::make_shared();
	std::weak_ptr 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;
}

我们可以看到源码是这样的:

weak_ptr 智能指针的使用_第1张图片

三,lock() 成员函数

shared_ptr lock() const noexcept; 函数返回一个shared_ptr,其中包含weak_ptr对象在未过期时保留的信息。如果 weak_ptr 对象已过期(包括它是否为空),该函数将返回一个空的shared_ptr(就像默认构造的一样)。

#include 
#include 
#include 

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 weakPtr;
    std::weak_ptr weakPtr2(weakPtr);
    std::shared_ptr ptr = std::make_shared();
    std::weak_ptr weakPtr3(ptr);

	std::shared_ptr lck;
	lck = weakPtr.lock();
	if(lck == nullptr)
	{
		printf("weakPtr is empty!\n");
	}

	if(!weakPtr2.lock())
	{
		printf("weakPtr2 is empty!\n");
	}

	std::shared_ptr 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。 

weak_ptr 智能指针的使用_第2张图片

我们可以看源码 lock() 函数是怎样实现的:

weak_ptr 智能指针的使用_第3张图片

可以看到当对象过期时,构造了一个空的 shared_ptr<>对象进行返回,而这个空对象它的初始化值是这样的:

weak_ptr 智能指针的使用_第4张图片

weak_ptr 智能指针的使用_第5张图片

_M_ptr 是模板参数类型的指针,它指向的就是要管理的对象。而 _M_refcount  是管理引用计数的。所以一个空的 shared_ptr<> 并不管理任何对象,就不能当作对象指针来用了。但 use_count() 还是可以用的,用 lck.use_count() == 0 进行判断:

weak_ptr 智能指针的使用_第6张图片

 weak_ptr 智能指针的使用_第7张图片

这里可能会有人疑问:lck 都是nullptr 了,怎么还能调用 use_count() 呢?这样调用不会崩溃吗?这个就要理解类与对象的关系了,可以参考 null 类对象。可以看源码:

四,use_count() 成员函数

weak_ptr 里有两个计数,一个是 _M_use_count 管理对象的引用计数,一个是 _M_weak_count 是不是用于它本身的析构用的,还没研究。weak_ptr 的基类:

weak_ptr 智能指针的使用_第8张图片

      _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;

weak_ptr 智能指针的使用_第9张图片

 _Sp_counted_base<_Lp> 就包含上述的两个计数。use_count() 函数调用的是_M_refcount._M_get_use_count(); 

weak_ptr 智能指针的使用_第10张图片

五,为什么要用 weak_ptr

1,解决shared_ptr 循环引用的问题。这个网上也有很多例子

2,在不延长shared_ptr 管理对象生命周期的情况下,探知这个对象是否已经无效。可以参考 muduo 的例子​​​​​​​

你可能感兴趣的:(#,智能指针,c++)