weak_ptr 智能指针的使用

2023-11-03

目录

一,weak_ptr 变量的定义

二,expired() 成员函数

三,lock() 成员函数

四,use_count() 成员函数

五,为什么要用 weak_ptr


一,weak_ptr 变量的定义

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

二,expired() 成员函数

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

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

三,lock() 成员函数

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 类对象。可以看源码:

四,use_count() 成员函数

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(); 

五,为什么要用 weak_ptr

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

weak_ptr 智能指针的使用 的相关文章

  • 有没有办法分析 WCF 应用程序的性能?

    我们正在尝试测量我们的系统的性能 该系统是一个使用 WCF 调用的 NET 3 5 应用程序 问题是到目前为止 我们无法分析这些调用中的方法 编写了一个 winforms 客户端应用程序来测试我们的系统 我们尝试使用ANTS 4 Profi
  • 即使我没有#include ,为什么仍然可以使用 std::max 和 std::min ?

    include
  • 如何在联系我们页面中使用用户电子邮件发送电子邮件?

    我正在创建一个联系我们页面 并且我想从该页面接收邮件 因为它的邮件来自用户邮件 我写了这段代码 var client new SmtpClient smtp gmail com 587 Credentials new NetworkCred
  • 将数据集导出到 EXCEL

    我使用以下代码将数据库表中的字段导出到 Excel 中 我想要做的是能够编写一条 SQL 语句从多个表中检索字段并将其导出到 Excel 中 这段代码只允许我导出一张表 另外 如何显示保存提示对话框 示例代码将不胜感激 非常感谢 prote
  • 实体框架 - 循环更新属性

    我正在尝试找到一种方法来循环 EF 对象的属性并更新这些属性的值 更具体地说 我有 50 个字段 其中最多填充 50 个下拉列表 所有 50 个可能都需要填充 也可能不需要填充 为了解决这个问题 我有一个中继器 最多可以创建 50 个 DD
  • 每个 CPU 核心处于 C0 电源状态的时间

    任何帮助弄清楚如何做到这一点都会很棒 在过去一秒内 每个 CPU 核心处于 C0 电源状态的时间有多少 这是针对 Mac 应用程序的 因此需要 Objective C cocoa 和 c OS X 没有任何公开 CPU c 状态的 API
  • 多个源文件中包含包含“const”的头文件

    Why does not包含定义的头文件const并被多个源文件包含会产生编译错误multiple definition const in header file h const int num 5 int x Error Multiple
  • 无法使用 Unity 函数在 Visual Studio Code 中获得完整的 Intellisense

    好吧 我知道这个问题已经被问过并回答过很多次了 但我花了大约 3 天的时间试图解决这个问题 但到目前为止我所做的一切都没有奏效 我基本上在 Visual Studio Code 中有部分智能感知 也就是说 它似乎只识别 Unity 类和变量
  • 在 C++ 中,严格别名规则中的“访问”是什么意思?

    3 10 10 说 如果一个程序试图access通过除以下类型之一之外的泛左值存储对象的值 行为未定义 然而 术语 访问 并没有在任何地方定义 在这种情况下这意味着read or 读取或修改 在 C 标准中 它被明确定义为读取或修改 然而在
  • 用 C++ 解密文件,该文件使用 openssl -aes-128-cbc 加密

    我正在尝试用 C 解密文件 该文件使用以下命令加密 openssl enc nosalt aes 128 cbc pass pass test in test txt out test enc txt p 控制台显示key 098F6BCD
  • C++ 克隆惯用语中协变返回类型的用处?

    通常的克隆习惯使用协变返回类型 struct Base virtual Base clone struct Derived public Base Derived clone 我读过一些内容 大意是协变返回类型是 C 后来添加的 较旧的编译
  • 使用经度和纬度查找给定距离内的所有附近客户

    我有一个包含客户经度和纬度的数据库 我有一个搜索表单 用户将在其中输入日志 纬度 距离下拉列表包含 50 英里 100 英里 当用户单击搜索时 我想编写一个 linq 查询从数据库中获取此距离半径内的所有客户 如何使用 C 和 linq 来
  • Xamarin 无法从异步获取实例

    我编写了一个通过蓝牙连接到 ESP32 的 Xamarin Forms 应用程序 现在我想从 MainPage xaml 页面的 CustomControl JoystickControl 获取值 我已经这样尝试过了 MainPage xa
  • 标准头文件中的 C 编译器错误 - 未定义的 C++ 定义

    我正在尝试编译 C 程序 但收到许多错误 这些错误是在标准 C 头文件 inttypes h stdio h stat h 等 中遇到的 错误的来源是以下未定义的常量 BEGIN DECLS END DECLS BEGIN NAMESPAC
  • 在 C# 中加密并在 Flex 中解密

    我需要解密 Flex 中的一些数据 这些数据是用 C 加密并写入文件的 为了简单起见 我选择使用 as3crypto As3 库和 Bruce Schneier C 库 AS3 as3加密链接 http code google com p
  • gcc 中的“假设”子句

    gcc 最新版本 4 8 4 9 是否有类似于以下的 假设 子句 assume 内置icc支持吗 例如 assume n 8 0 从 gcc 4 8 2 开始 gcc 中没有 assume 的等效项 我不知道为什么 这会非常有用 马夫索建议
  • 如何从标准输入读取一行,阻塞直到找到换行符?

    我试图从命令行的标准输入一次读取任意长度的一行 我不确定是否能够包含 GNU readline 并且更喜欢使用库函数 我读过的文档表明getline应该可以工作 但在我的实验中它不会阻塞 我的示例程序 include
  • 父窗体中的居中消息框[重复]

    这个问题在这里已经有答案了 有没有一种简单的方法可以在 net 2 0中将MessageBox居中于父窗体中 我在 C 中确实需要这个并发现中心消息框 C http bytes com topic c sharp answers 26712
  • 组合框由于某种原因被链接

    我有以下代码来填充 3 个组合框 private void PopulateDDLs SqlConnection connection SqlCommand command SqlDataReader reader DataTable dt
  • 你将如何开始自动化我的工作? - 第2部分

    后续这个问题 https stackoverflow com questions 2796128 how would you start automating my job 在经历了第一波进货 9 小时的复制 粘贴 后 我现在相信我已经满足

随机推荐