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

Doc*_*sha 15 c++ move-semantics c++11

这是来自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");
}
Run Code Online (Sandbox Code Playgroud)

该计划的输出是什么?

我想是这样的:

  1. f(X a)被调用,构造函数隐式转换const char*为X,因此输出为1
  2. 由于我们没有存储返回值的对象,因此返回值被丢弃,没有输出
  3. g(const char*)被调用,X c(b) X(const char*) 输出为1
  4. 返回值再被丢弃一次 - 没有输出

所以答案是11.给测验的答案是131.我用g ++ 4.4.4-13得到的答案是121.

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

g++ -std=c++11 -Wall -Wextra -O -pthread
Run Code Online (Sandbox Code Playgroud)

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

T.C*_*.C. 17

从理论上讲,这可以打印任何的131,13313,1313,和1331.作为一个测验问题,它非常愚蠢.

  • f("hello");:

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

    • "hello"用于c通过转换构造函数构造,打印1.
    • c用于初始化临时返回值,调用移动构造函数,打印3.这可以省略.

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

至于打印2,那是因为您使用的古代编译器没有实现隐式移动时返回局部变量规则.

  • 有没有理由为了初始化`f`的参数而必须使用临时(并且可能被省略)?为什么参数不能直接从参数初始化? (2认同)