c++ - gcc 和 clang 都省略了下面代码段中对移动构造函数的调用。这个对吗?

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

在下面的代码中,类 S 的对象 s 用于通过直接初始化 来初始化类 D 的对象>D d(s);。转换函数 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) 的第一个子项目符号点中,其中没有提及省略。

    If the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated (13.3.1.3), and the best one is chosen through overload resolution (13.3). The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.

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

最佳答案

C++ 标准喜欢在完全不同的地方为在一个地方定义的规则创建异常(exception)。

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

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

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

  • when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

关于c++ - gcc 和 clang 都省略了下面代码段中对移动构造函数的调用。这个对吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27249698/

相关文章:

ruby-on-rails - 组织 Rails 初始值设定项的更好方法

c++ - 如何在Eclipse CDT中选择文件进行调试?

c++ - C 编译 : error: stray '\4' in program ; octal flow?

C++ 如何对非常快的操作进行基准测试

c++ - 创建一个空的 shared_ptr 最简单的方法是什么?

c++ - 两个 map 之间的分配 - 移动语义和性能

multithreading - 初始化没有魔法静态的空多态单例类型

c - C 中已声明但未初始化的变量会发生什么情况?它有值(value)吗?

C++:模板成员函数,如 template<typename T> int foo<T>()

swift - 为什么 Swift 不允许在 class init 中给 self 赋值,而在 protocol init 中却不允许?