复制省略可以在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 语句之间发生吗? 的相关文章

随机推荐

  • QML WebEngineView 轻弹内容

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