【问题标题】:Why is the move-constructor not called?为什么不调用移动构造函数?
【发布时间】:2013-06-01 12:37:10
【问题描述】:

为什么在此示例中没有打印任何内容?我在 Coliru 上用 Clang 编译。

#include <iostream>

struct S
{
    S()    noexcept = default;
    S(S&&) noexcept { std::cout << "move-ctor"; }
};

void f(S) {}

int main()
{
    f(S{});
}

【问题讨论】:

标签: c++ c++11


【解决方案1】:

编译器正在执行复制省略,即使您的移动构造函数、复制构造函数或析构函数有副作用,这也是 C++11 标准第 12.8/31 段所允许的:

当满足某些条件时,允许实现省略类的复制/移动构造 对象,即使为复制/移动操作选择了构造函数和/或对象的析构函数 有副作用。

复制省略这个术语即使在移动被省略时也被使用:

这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(其中 可以合并以消除多个副本):

[...]

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

[...]

使用 GCC,您可以使用 -fno-elide-constructors 来禁止复制省略。在这种情况下,您会看到调用了移动构造函数,如 live example

【讨论】:

  • 移动时为什么叫复制省略?
  • @user2030677:这是标准术语。主要是出于历史原因(在 C++03 中只能省略副本,因为不存在移动语义)
  • @user2030677 您正在省略一个 copy,这可以使用复制构造函数或复制移动构造函数执行。
  • 另一个问题:如何阻止 RVO/NRVO 发生?有没有链接器选项?
  • @user2030677:RVO/NRVO 实际上是复制省略,所以在 GCC 上,这是我在答案末尾写的标志(顺便说一句,复制省略是编译器的工作,而不是链接器的工作)。在 Clang 上,标志是相同的,但该选项在 Clang 中有一个错误,所以我建议不要使用它。在 MSVC 上我不确定(也许尝试禁用 Debug 构建中的所有优化)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2014-01-24
  • 2023-03-16
相关资源
最近更新 更多