我试图理解移动语义和复制/移动省略。
我想要一个包含一些数据的类。我想在构造函数中传递数据并且我想拥有这些数据。
读完这个、这个和这个之后,我的印象是,在 C++11 中,如果我想存储一个副本,那么按值传递应该至少与任何其他选项一样有效(除了增加代码大小的小问题)。
然后,如果调用代码想避免复制,它可以通过传递一个右值而不是一个左值。(例如使用 std::move)
所以我试了一下:
#include <iostream>
struct Data {
Data() { std::cout << " constructor\n";}
Data(const Data& data) { std::cout << " copy constructor\n";}
Data(Data&& data) { std::cout << " move constructor\n";}
};
struct DataWrapperWithMove {
Data data_;
DataWrapperWithMove(Data&& data) : data_(std::move(data)) { }
};
struct DataWrapperByValue {
Data data_;
DataWrapperByValue(Data data) : data_(std::move(data)) { }
};
Data
function_returning_data() {
Data d;
return d;
}
int main() {
std::cout << "1. DataWrapperWithMove:\n";
Data d1;
DataWrapperWithMove a1(std::move(d1));
std::cout << "2. DataWrapperByValue:\n";
Data d2;
DataWrapperByValue a2(std::move(d2));
std::cout << "3. RVO:\n";
DataWrapperByValue a3(function_returning_data());
}
输出:
1. DataWrapperWithMove:
constructor
move constructor
2. DataWrapperByValue:
constructor
move constructor
move constructor
3. RVO:
constructor
move constructor
我很高兴在这些情况下都没有调用复制构造函数,但为什么在第二种情况下调用了额外的移动构造函数?我想任何像样的移动构造函数Data
都应该很快,但它仍然让我感到烦恼。我很想使用 pass-by-rvalue-reference (第一个选项),因为这似乎会导致更少的 move 构造函数调用,但如果可以的话,我想采用 pass-by-value 和复制省略。