复制省略可以在synchronize-with 语句之间发生吗?

2024-01-03

在下面的示例中,如果我们暂时忽略互斥锁,复制省略可能会消除对复制构造函数的两次调用。

user_type foo()
{
  unique_lock lock( global_mutex );
  return user_type(...);
}

user_type result = foo();

现在复制省略的规则没有提到线程,但我想知道它是否真的应该跨越这样的边界发生。在上面的情况下,逻辑抽象机线程间的最终副本发生在互斥体被释放之后。然而,如果省略副本,则结果数据结构将在互斥体中初始化,因此线程间发生在互斥体被释放之前。

我还没有想到一个具体的例子,复制省略如何真正导致竞争条件,但内存序列中的干扰似乎可能是个问题。任何人都可以明确地说它不会导致问题,或者有人可以提供一个确实可以破坏的示例吗?


为了确保答案不仅仅解决特殊情况,请注意,如果我有类似的声明,复制省略(根据我的阅读)仍然允许发生new (&result)( foo() )。那是,result不需要是堆栈对象。user_type它本身也可以处理线程之间共享的数据。


Answer:我选择第一个答案作为最相关的讨论。基本上,由于标准规定可能会发生省略,因此程序员在发生跨越同步边界的情况时必须小心。没有迹象表明这是有意还是无意的要求。我们仍然缺乏任何示例来说明可能出现的问题,所以也许这都不是问题。


线程与它无关,但锁的构造函数/析构函数的顺序可能会影响你。

查看代码执行的低级步骤,不进行复制省略,一一查看(使用 GCC 选项 -fno-elide-constructors):

  1. 构造lock.
  2. 搭建临时user_type with (...)论据。
  3. 复制构造函数的临时返回值,类型为user_type使用步骤 2 中的值。
  4. 销毁步骤 2 中的临时文件。
  5. Destroy lock.
  6. 复制构造user_type result使用步骤 3 中的值。
  7. 销毁步骤 3 中的临时文件。
  8. 后来毁了result.

当然,通过多重复制省略优化,它将只是:

  1. 构造lock.
  2. 构建result直接对象(...).
  3. Destroy lock.
  4. 后来毁了result.

请注意,在这两种情况下user_type构造函数与(...)受锁保护。任何其他复制构造函数或析构函数调用可能不受保护。

事后的想法:

我认为最有可能导致问题的地方是析构函数。也就是说,如果你的原始对象是用(...)以不同于其副本的方式处理任何共享资源,并在析构函数中执行需要锁的操作,那么就会遇到问题。

当然,这意味着您的对象首先设计得很糟糕,因为副本的行为与原始对象不同。

参考:

在 C++11 草案中,12.8.31(C++98 中的类似措辞没有所有“移动”:

当满足某些条件时,允许实现省略类的复制/移动构造 对象,即使对象的复制/移动构造函数和/或析构函数有副作用。在这种情况下, 该实现将省略的复制/移动操作的源和目标视为两个不同的 引用同一对象的方式,并且该对象的销毁发生在较晚的时间 如果不进行优化,这两个对象就会被销毁。复制/移动的省略 称为复制省略的操作在以下情况下是允许的(可以组合起来) 消除多个副本):

  • 在具有类返回类型的函数的 return 语句中,当表达式是 a 的名称时 具有相同 cvunqualified 的非易失性自动对象(函数或 catch 子句参数除外) type 作为函数返回类型,可以通过构造省略复制/移动操作 自动对象直接进入函数的返回值

  • 函数或 catch 子句参数),其范围不超出最内层的末尾 封闭 try 块(如果有),从操作数到异常的复制/移动操作 可以通过直接将自动对象构造到异常对象中来省略对象

  • 当复制/移动尚未绑定到引用的临时类对象时 对于具有相同 cv-unqualified 类型的类对象,可以通过以下方式省略复制/移动操作 将临时对象直接构造到省略的复制/移动的目标中

  • 当异常处理程序的异常声明声明相同类型的对象时 (除了 cv 限定)作为异常对象,如果程序的含义可以通过将异常声明视为异常对象的别名来省略复制/移动操作 除了执行声明的对象的构造函数和析构函数之外,将保持不变 异常声明。

第 1 点和第 3 点在您的示例中协作删除所有副本。

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

复制省略可以在synchronize-with 语句之间发生吗? 的相关文章

  • JQuery、ASCX 和 webmethods 似乎不起作用

    我有一个级联下拉列表 其中 3 个 类型 类别和子类别 首先类型负载 然后选择类型 类别负载以及选择类别 子类别负载 我还有 2 个按钮 添加类别 和 添加子类别 单击这些按钮后 我调用 JQuery 模态表单来添加它们 我在代码后面使用
  • 如何在 ASP.Net Core 6 Web Api 中依赖注入 Microsoft Graph 客户端

    我正在尝试使用 ASP Net Core 6 设置 Web api 以便用户可以到达我的端点 然后我使用特权帐户在 Teams 中执行一些工作 我认为我没有正确连接 DI 部分 因为在向 Teams 发出请求时出现以下错误 MsalUiRe
  • 进入嵌入式[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何设置 web.config 文件以显示完整的错误消息

    我在 Windows Azure 上部署了 MVC 3 应用程序 但现在当我通过请求时staging url它告诉我 很抱歉 在执行您的要求时发生了一个错误 现在我想查看完整的错误消息 默认情况下由于某些安全原因它会隐藏该消息 我知道我们可
  • 忽略父进程中的信号

    我正在尝试实现一个 shell 程序 我希望 shell 程序忽略 SIG INT ctrl c 但在我的程序中 子进程也会忽略 SIG INT 信号 但它不应该这样做 因为 exec 应该将子进程带到另一个程序 并且该程序默认情况下应该处
  • 合并多边形的高效算法

    我有一个多边形列表 在这个列表中 一些多边形重叠 或者接触其他多边形 我的任务是合并所有相互重叠或接触的多边形 我有一个union执行此操作的方法 做到这一点最有效的方法是什么 我目前能想到的是循环遍历多边形列表 检查合并列表以查看该多边形
  • 有什么办法可以让这个 C# 代码更快吗? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在读取一个大文件 X12 并解析其中的信息 我有两个瓶颈功能 我似乎无法解决 read line 和 get element 有什
  • 如何使用平台调用编组 void*

    我需要从 dll 中包含的 C api 调用函数 函数原型如下 int func char name void value 其中指针值的内容可以引用依赖于传递的名称的任何类型 我不确定如何设置 Dll 输入端口以正确编组此 void 我一直
  • C++ 中的反向迭代器和负跨步迭代器,在开始之前使用一个作为哨兵

    In 查看 C 反向迭代器的另一种方式 https devblogs microsoft com oldnewthing 20211112 00 p 105908雷蒙德 陈写道 C 语言的一个怪癖 你可以拥有一个指针 集合的 已过终点 但不
  • 在“delete this;”语句期间发生了什么?

    请考虑以下代码 class foo public foo foo void done delete this private int x 以下两个选项中发生了什么 并且有效吗 选项1 void main foo a new foo a gt
  • ICSharpCode.Decompiler + Mono.Cecil -> 如何为单个方法生成代码?

    我可以使用 Mono Cecil 和 ICSharpCode Decompiler 生成类型或程序集的代码 但是 如果我尝试为单个方法生成代码 我将收到错误 对象引用未设置为对象的实例 你们能给我任何关于这个的提示吗 提前感谢您的所有帮助
  • FxCop 和 GAC 疯狂

    当我尝试分析依赖于模式和实践 企业库数据 以及其他 2 0 0 0 的项目时使用 FxCop FxCop 抱怨它不能 定位程序集引用 即使正在分析的应用程序 dll 是根据其编译的此版本及其在 GAC 中 如果我浏览到 GAC 尝试选择相同
  • 使用标准范围连接带有分隔符的字符串范围

    我想使用范围将跨度中包含的四个字节转换为字符串 这是输入和输出的示例 std span
  • 如何声明返回相同类型的 Func Delegate 的 Func Delegate?

    我想编写一个方法 该方法可以完成一些工作 并最终返回另一个与原始方法具有相同签名的方法 这个想法是根据前一个字节值顺序处理字节流 而不进行递归 通过这样调用它 MyDelegate executeMethod handleFirstByte
  • 在 C++ 中运行 python [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一个用 C 编写的应用程序和一个测试系统 也是用 C 编写的 测试系统非常复杂并且很难改变 我只想做一些小的改变 我的班级是这样的
  • 是否有普遍接受的 GMP 替代方案来实现任意精度? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 在寻找 BigInt 库的过程中 我发现了这篇文章 Microsoft Windows 上的 C 或
  • 我的 C 程序无法运行,并显示“无法执行二进制文件:Exec 格式错误”

    我刚刚从 C 开始 我试图编译下面的代码并执行它 但出现错误 也在运行sizeBS 或数据堆栈中没有显示任何内容 include
  • TransactionScope 在某些机器上自动升级到 MSDTC?

    在我们的项目中 我们使用 TransactionScope 来确保我们的数据访问层在事务中执行其操作 我们的目标是not要求在我们的最终用户的计算机上启用 MSDTC 服务 问题是 在我们一半的开发人员机器上 我们可以在禁用 MSDTC 的
  • 删除指针后将其设为 NULL 是一个好习惯吗?

    我首先要说的是 使用智能指针 您将永远不必担心这个问题 下面的代码有什么问题 Foo p new Foo use p delete p p NULL 这是由答案和评论 https stackoverflow com questions 19
  • 从 C# 应用程序调用 ASP.net Web 服务

    我有个问题 我如何调用 Web 服务并从 C 桌面应用程序获取结果 我正在制作一个桌面应用程序 我希望它能够连接到我的在线 ASP net Web 服务 这怎么可能 在 解决方案资源管理器 中 右键单击项目节点并选择 添加 Service参

随机推荐

  • QML WebEngineView 轻弹内容

    我正在尝试使用 QML 和 WebEngineView 组件使用 Ubuntu 14 04 制作一个简单的桌面网络浏览器 该应用程序将在带有触摸板的设备上运行 因此最好使 WebEngineView 中显示的内容可滑动 我尝试这样做 但它不
  • 为什么“