Ari*_*Ari 1 c++ move-semantics c++11
我们知道 std::move实际上并没有移动任何东西。它只是将左值引用 (&) 转换为右值引用 (&&)。
那么在下面的例子中,复制构造函数是如何调用的呢?如果没有移动构造函数,那么构造使用 std::move() 的对象如何依靠复制构造函数?变量的绑定究竟是如何b发生的?
struct Test {
// Default constructor
Test() {
std::cout << "Constructor is called." << std::endl;
mValue = 0;
}
// Copy constructor
Test(const Test& rhs) {
std::cout << "Copy Constructor is called." << std::endl;
mName = rhs.mName;
mValue = rhs.mValue;
}
std::string mName;
int mValue;
};
int main() {
Test a;
Test b = std::move(a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
Constructor is called.
Copy Constructor is called.
Run Code Online (Sandbox Code Playgroud)
我们来类比一下。考虑一下这段代码:
void doSomething(const int& x) {
std::cout << "You like " << x << "? That's my favorite number!" << std::endl;
}
int main() {
doSomething(137); // <-- Here
}
Run Code Online (Sandbox Code Playgroud)
现在,重点关注 中的呼叫main。这段代码编译并运行得很好,但有一些奇怪的地方。请注意,它doSomething接受一个const int&. 这意味着它接受对 的引用int,并且引用(通常)仅绑定到左值。但这里的参数 137 是一个右值。是什么赋予了?
这样做的原因是 C++ 语言特别允许const左值引用绑定到右值,即使常规左值引用不能。例如:
const int& totallyLegal = 137; // Yep, that's fine!
int& whoaNotCoolMan = 42; // Compile error!
Run Code Online (Sandbox Code Playgroud)
您可以这样做有几个原因。如果您有const左值引用,则您已承诺可以查看引用的对象,但不能修改它。因此,将左值引用绑定到右值是安全的,因为这样您就无法获取“纯值”并为其分配某些内容。从历史上看,在 C++11 之前,当右值引用不存在时,这使得可以使用左值编写这样的函数:“请以不涉及复制的方式将此参数传递给我const”参考。
现在我们有了左值引用,这条规则引入了一些以前不存在的混乱点。特别是, aconst T&可以绑定到任何类型的表达式的结果T,即使它是 aT&或 a T&&。这就是在您的情况下选择复制构造函数的原因。
不过,这里还有一个细微差别。就像 C++ 编译器会自动为类定义默认构造函数、复制构造函数和赋值运算符(如果您自己不这样做)一样,C++ 编译器也可以自动定义移动构造函数。但是,有一条规则规定,如果类型具有用户定义的复制构造函数,则编译器不会为您生成移动构造函数。因此,您问题的完整答案是“复制构造函数的存在意味着没有定义移动构造函数,并且由于复制构造函数接受const左值引用,因此它将绑定到右值以及左值。”
| 归档时间: |
|
| 查看次数: |
1285 次 |
| 最近记录: |