我正在阅读 Stroustrup 的《编程:C++ 原理与实践》第 4 版,我对一些旨在说明复制构造函数/复制赋值/移动构造函数/移动赋值/析构函数语言功能的代码的输出感到困惑。 以下代码大部分取自书中,并实现了一个简单类型
X
,以便上述运算符(以及构造函数)在调用时输出显式信息。
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::string;
using std::vector;
struct X {
int val;
void out(const string& s, int nv) {
cout << this << "->" << s << ":" << val << "(" << nv << ")\n";
}
X() { out("X()",0); val=0; }
explicit X(int x) { out("X(int)",x); val=x; }
X(const X& x) { out("X(X&)", x.val); val=x.val; }
X& operator=(const X& x) {
out("X copy assignment", 0);
val=x.val;
return *this; }
X(X&& x) {
out("X(X&&)",x.val);
val = x.val;
x.val = 0;
}
X& operator=(X&& x) {
out("X move assignment", x.val);
val = x.val;
x.val = 0;
return *this;
}
~X() { out("~X()", 0); }
};
X copy(X a) {
cout << "copy()\n";
return a;
}
int main() {
X loc {4};
X loc2 {12};
loc2 = copy(loc);
cout << "Done\n";
}
运行该程序时看到的输出如下:
0x16d1370bc->X(int):1(4)
0x16d1370b8->X(int):-1834548312(12)
0x16d1370b0->X(X&):1829990608(4)
copy()
0x16d1370b4->X(X&&):1(4)
0x16d1370b8->X move assignment:12(4)
0x16d1370b4->~X():0(0)
0x16d1370b0->~X():0(0)
Done
0x16d1370b8->~X():4(0)
0x16d1370bc->~X():4(0)
我理解这个输出的前四行——它们来自两个局部变量
loc
和loc2
的构造函数,来自copy
值调用的复制构造函数,以及来自copy
函数体。 我对下一行感到困惑——即对移动构造函数的调用。 我本以为只会看到对移动赋值运算符的调用。 为什么在这里调用移动构造函数(我不认为有任何对象正在被构造?)?这是在呼吁什么?特别是,我没有看到带有移动构造函数打印的内存地址的对象的构造,所以我很困惑该对象来自哪里。
感谢您的帮助,很抱歉我是 C++ 新手。 如果相关的话,我正在用
g++ -Wall -std=c++20
编译这个程序。 使用不同的编译优化级别,输出仍然存在。
正如您的输出所示,表达式
loc2 = copy(loc)
涉及复制、移动和赋值:
loc
用于复制构造 a
的
copy
a
中的局部对象copy
用于移动构造copy
的返回值。copy
返回值的引用作为 x
参数传递给 X
的移动赋值运算符如果我不得不猜测,您不会将
copy
的返回值视为一个不同的对象。 在许多情况下,这是准确的,因为复制删除会删除该特定副本。 如果您返回纯右值(即 return X{42};
)并使用 C++17 或更高版本,则该优化是强制性的,但在返回命名对象时它是可选的,因为在 100% 的情况下这是不可能的。