在构造函数中注册weak_ptr观察者

2023-12-28

我正在尝试重写我们的 Observer / Observable 实现,以使用 std::shared_ptr/std::weak_ptr 来消除代码中当前存在的一些令人讨厌的竞争条件。

通常,观察者在满足某些条件或构造子对象时注册自己,如下所示:

// Used to be raw 'this' now child instead derives a weak_ptr and stores it
child->addObserver(shared_from_this()) 

并在析构函数中注销自己,如下所示:

child->removeObserver(this); // Not shared_from_this() since in destructor

在某些情况下,这工作得很好,但是在许多情况下,观察者希望在构造函数中注册自己。由于shared_ptr尚未创建,我们无法调用shared_from_this()。

由于weak_ptr通常被推荐在C++中实现观察者模式,我想知道解决上述问题的惯用方法是什么。

一些想法:

  • 让创建观察者对象的工厂注册观察者。这会泄漏观察者的抽象(为什么工厂应该知道孩子想要观察谁?)并迫使观察者公开它可能想要观察的内部对象
  • 添加一个 init 方法,该方法在构造函数完成后由工厂调用,比上面更好,但是构造函数和 init 之间的语义区别是什么?应该在哪里做什么?甚至是 RAII 吗?事实上,有些语言甚至将它们的构造函数称为 init。
  • 将 lambda 传递给构造函数,该构造函数采用另一个在构造后调用的 lambda
  • 也许有一些模板魔法?
  • 以其他方式实现观察者模式。

处理您所要求的问题的一种方法是创建一个由 a 持有的显式观察者对象实例shared_ptr并包含在“父”中。观察者对象会将观察结果发送给父对象。

然而,由于孩子正在注册shared_ptr to a weak_ptr,实际上父级不需要显式地删除自己作为观察者。当孩子向观察者发送通知时,它会检查是否weak_ptr首先是有效的。如果不再有效,它可以就地移除观察者而不是通知。

void notify_observers (Event e) const {
    auto o = observers_.begin();
    auto erase = [this](decltype(o) o) {
        return observers_.erase(o);
    };
    while (o != observers_.end()) {
        if (auto l = o->lock()) ++o, l->notify(e);
        else o = locked_call(erase, o);
    }
}

在线尝试一下! https://tio.run/##fVTRbtowFH3nK@6Y1JoVkLZHYJGmCW0PlUDbY1sh41zAqhOniUOLEPt1dm2HxF7b5QES@9zjc869iSiK0VaI80eZC1WnCDOpK1Miz5Jet5ZhpstDuKJkZSJEbfAlOWNeZzDfY27gCD/nt7cLOE17PWKshYElL91OD@iqTDqZVDtaSleFKWd@M4EK1WY1dZAGzwYw8cvM7GQ1hLsHNh6PB8fTAI6nCCl0XrXnXNk6f89a5J@O9CukuOG1MtFpV6ALLLnRJQFeER6hRFOXOXyyUqbgSfdappBrIzcHYN4@DhqfrVehawOzGdhC@9@fwFYT0MH7dgXtz/V9fu0Fee5WzXuBkROvstXmI6T6IPvvO6nSRhI1i68VekbXOVBaPDapR7u2zzN394z8MTw3Ab2usNxjWTWFBrNCcUMuzKHAnGcIi@UQLg/UMvj268fvxIF5bbQ7ldwIrhSwxZK8Dh3EQnm5rS7ORgm1SijLxHTB7JYdgFcROxfbmpfprPOWwJa5jcG0RTdBBVxh5D6rbmZce3maLhrDwN7rRRFKchaLutqt1lw80jTd2dY/sNYKoYtgpLo8x20VYab2FbpwBomxFjQkmlB/MI6rljQYzGZcYqGaBAYK1riVOQsicyAaxQrfcKIHoN924ipoP3LxTAEjMA0fojMxT1nUVHvJDTA/LFbgKLEJWNTNjR6CGiXeJ8NAqr1QkVDrKUzMiRmS1A57anKzr4qkeDIuc9f6YBJE9IEo/JMYBxPBLg3otDfop@6ouOIpEBF9H/qjEcxfCqSX9ovvohTcSOrZfd4P2f7tMHMf3GgS3iP@HBG3vP/hPJ3PfwE

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

在构造函数中注册weak_ptr观察者 的相关文章

  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • 如何从 Visual Studio 将视图导航到其控制器?

    问题是解决方案资源管理器上有 29 个项目 而且项目同时具有 ASP NET MVC 和 ASP NET Web 表单结构 在MVC部分中 Controller文件夹中有大约100个子文件夹 每个文件夹至少有3 4个控制器 视图完全位于不同
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • C# 列表通用扩展方法与非通用扩展方法

    这是一个简单的问题 我希望 集合类中有通用和非通用方法 例如List
  • 两个静态变量同名(两个不同的文件),并在任何其他文件中 extern 其中一个

    在一个文件中将变量声明为 static 并在另一个文件中进行 extern 声明 我认为这会在链接时出现错误 因为 extern 变量不会在任何对象中看到 因为在其他文件中声明的变量带有限定符 static 但不知何故 链接器 瑞萨 没有显
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • 如何实例化 ODataQueryOptions

    我有一个工作 简化 ODataController用下面的方法 public class MyTypeController ODataController HttpGet EnableQuery ODataRoute myTypes pub
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • C++ 中的参考文献

    我偶尔会在 StackOverflow 上看到代码 询问一些涉及函数的重载歧义 例如 void foo int param 我的问题是 为什么会出现这种情况 或者更确切地说 你什么时候会有 对参考的参考 这与普通的旧参考有何不同 我从未在现
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐

  • Javascript 在新窗口中打印不会显示图像

    我正在努力解决一个问题 我希望你能帮助我 我创建了一个函数 可以打印页面中输入的数据 但是 我在打印页面上使用的徽标不会显示 就像图像的链接已损坏一样 有什么想法吗 这是代码 function printReport win null va
  • Scala:分隔延续解释 - 不

    对延续的概念感兴趣 我开始阅读维基 帖子 并找到了这个 简单 的例子 reset shift k Int gt Int gt the continuation k will be the 1 below k 7 1 result 8 如果不
  • 如何开始在 .NET 中创建应用程序 API

    在我工作的公司中 我们有一个用 NET 开发的桌面应用程序 我们希望为其他软件开发人员开放一些部分 我将其视为其他软件可以访问的某种公共方法 有没有这方面的标准方法 最佳实践或其他经验 我想你可以通过 Win32 调用 C C 编程等来做到
  • 如何/在哪里定义 AudioWorkletProcessor

    我刚刚开始使用 Web Audio API 我仔细阅读了 API 文档并看到了几个示例 我的问题可能很微不足道 而且我可能错过了一些基本的东西 我有下面的工作者 javascript 文件 它来自一个我放错了网址的示例 我正在使用 PyCh
  • R“图像”函数的意外转置翻转输出

    假设我有一个矩阵 m lt matrix 1 5 4 5 m 1 2 3 4 5 1 1 5 4 3 2 2 2 1 5 4 3 3 3 2 1 5 4 4 4 3 2 1 5 现在 当我这样做时 image m 我得到了意想不到的输出 所
  • Xamarin.Forms:Visual Studio 升级后的部署问题

    将 Visual Studio Professional 2019 升级到版本 16 9 2 后 当我尝试在 Android 模拟器上部署时 api 28 9 0 我收到以下错误 Error XA0130 Sorry Fast deploy
  • 如何处理看起来像SQL关键字的SQL列名?

    我的专栏之一叫做from 我无法更改名字 因为我没有成功 我可以做类似的事情吗SELECT from FROM TableName或者是否有特殊的语法来避免 SQL Server 被混淆 将列名称括在括号中 如下所示 from变成 来自 s
  • 使用 RDD 中的索引扫描 Spark 中的 Hadoop 数据库表

    那么如果数据库中有一张表如下所示 Key2 DateTimeAge AAA1 XXX XXX XXX AAA2 XXX XXX XXX AAA3 XXX XXX XXX AAA4 XXX XXX XXX AAA5 XXX XXX XXX A
  • 字典中一个键存储多个值

    我有一个数据列表 其中有 2 个值 a 12 a 11 a 5 a 12 a 11 我想使用字典 这样我就可以得到每个键的值列表 第 1 列可能有不同的条目 例如 b 所以我可以根据第1列作为键来排列数据 而第2列是每个键的数据 a 12
  • 为什么 Rails 中不推荐使用 auto_link?

    我意识到它已被拉入单独的宝石中 但原因是什么 这只是简化 Rails 的问题 还是有什么原因让我应该厌倦 auto link gem 说它的目的是 为人们迁移弥合差距 这对我来说意味着 如果我将 Rails autolink 引入到一个新项
  • iPhone 本地存储空间有限制吗?

    我想知道 iPhone 上 localstorage HTML 5 的限制是什么 我读到它大约是 5 Mb 但令我惊讶的是这么小 有任何想法吗 MobileiPhone 和 iPad 上的 Safari 在抛出错误之前将保留 5MBQUOT
  • 无法将队列添加到现有 TFS 2015 构建代理池

    升级到 TFS 2015 后尝试设置构建服务器 我设想的方式是 单代理池 将有 3 个队列 1 每晚构建 2 CI构建 3 门控 验证构建 他们每个人都会有一些代理 目标是进行一些控制 以确保夜间构建不会消耗所有代理 因此门控队列将始终有一
  • SVN合并重新整合缺失的范围但没有要合并的内容

    这是谜语 C code trunk gt svn merge reintegrate http svn e com repos branches lih accept postpone dry run svn E195016 Reinteg
  • PHP:如何查找字符串中 * 通配符的出现

    也许我问的问题有点太平庸了 但我真的不知道如何使用 PHP 检查字符串中是否出现通配符 字符 示例字符串 bcd OR ab d OR abc 无论我尝试使用什么 PHP 函数 它的行为都是不可预测的 我只需要知道通配符是否在字符串中 非常
  • 从 AsyncTask 管理 ProgressDialog 的最佳方法

    我想使用AsyncTask用于管理我的应用程序中的一些业务逻辑 使用的最佳模式是什么onProgressUpdate 的方法AsyncTask在单独的文件中定义 不是作为内部类Activity 我有两个想法 1 最简单的方式 创建Progr
  • 保护控制器除一个(登录)之外的所有操作的最佳方法是什么?

    目前我有 Authorize 我的所有方法的属性AdminController除了Logon action 什么是cleanest反转这个的方法 所以我不必记住向所有方法添加属性 而是仅向无需登录即可使用的方法添加属性 我会更好地移动Log
  • 为什么我在使用 MockMvc 和 JUnit 时收到错误 403?

    我有一个带有 spring security 3 2 的 spring mvc 3 2 5 应用程序 我用这个方法配置了我的 SecurityConfig class Override protected void configure Ht
  • 笔记本电脑触控板的 WM_INPUT 上的 RAWINPUTHEADER hDevice 为 null

    我使用原始输入来处理通用设备的输入 到目前为止 我的所有测试用例都有效 键盘 游戏板和鼠标 但我的笔记本电脑触控板给我带来了一个奇怪的问题 当我得到一个WM INPUT https learn microsoft com en us win
  • 创建 Windows 服务的最简单语言

    构建 Windows 服务最简单的语言是什么 在这种情况下 最简单的定义是最少的代码量和最低的语言入口点 冒着陈述显而易见的风险 如果您有任何 C C Java 背景 我认为 C 为您提供了最低的切入点 假设您使用的是 Visual Stu
  • 在构造函数中注册weak_ptr观察者

    我正在尝试重写我们的 Observer Observable 实现 以使用 std shared ptr std weak ptr 来消除代码中当前存在的一些令人讨厌的竞争条件 通常 观察者在满足某些条件或构造子对象时注册自己 如下所示 U