【问题标题】:gcc and clang both elide the call to the move constructor in the snippet below. Is this correct?gcc 和 clang 都在下面的代码片段中省略了对 move 构造函数的调用。它是否正确?
【发布时间】:2015-01-30 17:11:08
【问题描述】:

在下面的代码中,S 类的对象s 用于通过直接初始化D d(s); 来初始化D 类的对象。转换函数 S::operator D() 用于将对象s 转换为D 类型的临时对象。然后,gcc 和 clang 都省略了对移动构造函数D(&&) 的显式调用,将这个临时对象移动到d。见live example

#include <iostream>
struct D;
struct S{ operator D(); };

struct D{
    D(){}
    D(D&&) { std::cout << "move constructor" << '\n'; }
};

S::operator D() { std::cout << "conversion function" << '\n'; return D(); }

int main()
{
    S s;
    D d(s);
}

我对这种省略的正确性提出异议,理由如下:

  1. 第 8.5/16 节 (N3337) 中的第一个子项目符号对此案例进行了介绍,其中没有提及省略。

    如果初始化是直接初始化,或者如果是 复制初始化,其中源的 cv 不合格版本 type 与该类的类相同或派生类 目的地,构造函数被考虑。适用的构造函数 枚举(13.3.1.3),通过重载选择最好的 决议(13.3)。调用如此选择的构造函数进行初始化 对象,以初始化表达式或表达式列表作为其 论点。如果没有构造函数适用,或者重载决议是 模棱两可,初始化格式不正确。

  2. 请注意,下一个子要点明确提到了省略的可能性。
  3. 对移动构造函数的调用是显式的。怎么能去掉?

【问题讨论】:

    标签: c++ c++11 initialization language-lawyer copy-elision


    【解决方案1】:

    C++ 标准喜欢为在一个完全不同的地方定义的规则创建例外。

    复制/移动省略规则在 12.8/31 中指定。您的代码中有两个复制/移动操作要消除。

    第一个很简单:在operator D 中,将return 表达式中构造的临时值移动到表示函数返回值的临时值。 Bullet 3 允许省略这一举动。

    第二个是将临时函数返回值移动到d对象。同样,第 3 条允许省略。

    • 当一个没有绑定到引用 (12.2) 的临时类对象将被复制/移动到具有相同 cv-unqualified 类型的类对象时,可以通过直接构造临时对象来省略复制/移动操作进入省略的复制/移动的目标

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-25
      • 2018-06-08
      • 2015-07-02
      • 1970-01-01
      • 1970-01-01
      • 2021-09-01
      • 1970-01-01
      • 2014-01-05
      相关资源
      最近更新 更多