为什么移动构造函数在这里调用?

时间:2015-08-12 07:26:23

标签: c++ c++11 move-semantics

以下是C ++测验的代码示例:

#include <iostream>
struct X {
    X(const char *) { std::cout << 1; }
    X(const X &) { std::cout << 2; }
    X(X &&) { std::cout << 3; }
};

X f(X a) {
    return a;
}

X g(const char * b) {
    X c(b);
    return c;
}

int main() {
    f("hello");
    g("hello");
}

该计划的输出是什么?

我想是这样的:

  1. f(X a)被调用,构造函数隐式将const char*转换为X,因此输出为1
  2. 由于我们没有存储返回值的对象,因此丢弃返回值,无输出
  3. g(const char*)被调用,X c(b) X(const char*) 输出为1
  4. 返回值再被丢弃一次 - 无输出
  5. 所以答案是11.给测验的答案是131.我用g ++ 4.4.4-13得到的答案是121。

    据说这段代码是用这个命令编译的:

    g++ -std=c++11 -Wall -Wextra -O -pthread
    

    中间数字来自哪里?为什么它可以是3或2?

2 个答案:

答案 0 :(得分:17)

理论上,这可以打印1311331313131331中的任何一个。作为测验问题,它非常愚蠢。

  • f("hello");

    • &#34;你好&#34;通过转换构造函数转换为临时X,打印1
    • 临时X用于初始化函数参数,调用移动构造函数,打印3。这可以省略。
    • x用于初始化临时返回值,调用移动构造函数,打印3。它是一个函数参数,因此不允许使用省略,但返回是隐式移动。
  • g("hello");

    • &#34;你好&#34;用于通过转换构造函数构造c,打印1
    • c用于初始化临时返回值,调用移动构造函数,打印3。这可以省略。

请记住,函数总是必须构造它们返回的东西,即使它只是被调用代码丢弃了。

关于打印2,因为你使用的古老编译器并没有实现隐式移动时返回本地变量规则。

答案 1 :(得分:3)

Copy elision适用于return中的g语句,也可能适用于其他地方。引自cppreference:

  

复制省略是唯一可以改变的优化形式   可观察到的副作用。因为有些编译器不能执行   在允许的每种情况下复制省略(例如,在调试中)   模式),依赖于复制/移动的副作用的程序   构造函数和析构函数不可移植。

因此,对于您的示例代码,无法在不同的实现中可靠地预测输出。