为什么要在这里调用移动构造函数?
Why is the move constructor called here?
这是来自 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");
}
程序的输出是什么?
我是这样认为的:
f(X a)
被调用,构造函数将const char*
隐式转换为X,所以输出为1
- 由于我们没有对象来存储return值,return值被丢弃,没有输出
g(const char*)
被调用,X c(b)
X(const char*)
输出为1
- return值又被丢弃了一次 - 没有输出
所以答案是 11。测验的答案是 131。我用 g++ 4.4.4-13 得到的答案是 121。
据说这段代码是用这条命令编译的:
g++ -std=c++11 -Wall -Wextra -O -pthread
中间的数字从何而来?为什么可以是 3 或 2?
Copy elision 适用于 g
中的 return
语句,也可能适用于其他地方。引用自 cppreference:
Copy elision is the only allowed form of optimization that can change
the observable side-effects. Because some compilers do not perform
copy elision in every situation where it is allowed (e.g., in debug
mode), programs that rely on the side-effects of copy/move
constructors and destructors are not portable.
因此,对于您的示例代码,无法跨不同的实现可靠地预测输出。
理论上,这可以打印131
、13313
、1313
和1331
中的任何一个。作为一个测验问题,这很愚蠢。
f("hello");
:
- "hello" 通过转换构造函数转换为临时
X
,打印 1
.
- 临时
X
用于初始化函数参数,调用移动构造函数,打印3
。这可以省略。
x
用于初始化临时return值,调用移动构造函数,打印3
。这是一个函数参数,所以不允许省略,但是 return 是一个隐式移动。
g("hello");
- "hello" 用于通过转换构造函数构造
c
,打印 1
.
c
用于初始化临时return值,调用移动构造函数,打印3
。这可以省略。
请记住,函数总是必须构造它们 return 的东西,即使它只是被调用代码丢弃。
至于打印 2
,那是因为您使用的古老编译器没有实现 implicit-move-when-returning-a-local-variable 规则。
这是来自 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");
}
程序的输出是什么?
我是这样认为的:
f(X a)
被调用,构造函数将const char*
隐式转换为X,所以输出为1- 由于我们没有对象来存储return值,return值被丢弃,没有输出
g(const char*)
被调用,X c(b)
X(const char*)
输出为1- return值又被丢弃了一次 - 没有输出
所以答案是 11。测验的答案是 131。我用 g++ 4.4.4-13 得到的答案是 121。
据说这段代码是用这条命令编译的:
g++ -std=c++11 -Wall -Wextra -O -pthread
中间的数字从何而来?为什么可以是 3 或 2?
Copy elision 适用于 g
中的 return
语句,也可能适用于其他地方。引用自 cppreference:
Copy elision is the only allowed form of optimization that can change the observable side-effects. Because some compilers do not perform copy elision in every situation where it is allowed (e.g., in debug mode), programs that rely on the side-effects of copy/move constructors and destructors are not portable.
因此,对于您的示例代码,无法跨不同的实现可靠地预测输出。
理论上,这可以打印131
、13313
、1313
和1331
中的任何一个。作为一个测验问题,这很愚蠢。
f("hello");
:- "hello" 通过转换构造函数转换为临时
X
,打印1
. - 临时
X
用于初始化函数参数,调用移动构造函数,打印3
。这可以省略。 x
用于初始化临时return值,调用移动构造函数,打印3
。这是一个函数参数,所以不允许省略,但是 return 是一个隐式移动。
- "hello" 通过转换构造函数转换为临时
g("hello");
- "hello" 用于通过转换构造函数构造
c
,打印1
. c
用于初始化临时return值,调用移动构造函数,打印3
。这可以省略。
- "hello" 用于通过转换构造函数构造
请记住,函数总是必须构造它们 return 的东西,即使它只是被调用代码丢弃。
至于打印 2
,那是因为您使用的古老编译器没有实现 implicit-move-when-returning-a-local-variable 规则。