我正在从《C++ Move Semantics》一书中阅读有关 C++ 中的移动语义的内容。本书假设
NRVO
用于 createAndInsert()
函数的 return 语句中。但是,它还指出,当在 v = createAndInsert();
中执行 main()
时,将应用移动语义。
我的问题是:如果已经应用了 NRVO,是否应该直接在
coll
的空间中构造 v
,从而使 main()
中不需要任何移动操作?这可能是为了书中的学习目的,还是暗示如果不应用 NRVO
会发生什么,尽管它已经声明了?我试图了解我是否遗漏了有关 NRVO 和移动语义在这种情况下如何交互的信息。
感谢您的见解!
#include <string>
#include <vector>
std::vector<std::string> createAndInsert()
{
std::vector<std::string> coll; // create vector of strings
coll.reserve(3); // reserve memory for 3 elements
std::string s = "data"; // create string object
coll.push_back(s); // insert string object
coll.push_back(s+s); // insert temporary string
coll.push_back(std::move(s)); // insert string (we no longer need the value of s)
return coll; // return vector of strings
}
int main()
{
std::vector<std::string> v; // create empty vector of strings
//...
v = createAndInsert(); // assign returned vector of strings
//...
}
如果您要执行
std::vector<std::string> v = createAndInsert();
,首先会从 coll
移动到返回的临时文件(NRVO 可能会或可能不会删除它),然后从该临时文件再次移动到 v
(这总是被删除,因为C++17).
但是在执行
std::vector<std::string> v; v = createAndInsert();
时,第二个动作永远无法被省略,因为对象已经构造好了。
v = createAndInsert();
与 v.operator=(createAndInsert());
完全相同。 createAndInsert()
的返回值绑定到移动赋值运算符的 std::vector<std::string>&&
参数,因此必须将其移出。
operator=
与任何其他功能没有什么不同。如果有一个名为 f
的成员函数想要从其参数进行赋值,则 v.f(createAndInsert())
必须创建另一个对象来传递给该函数。只有这样才能摆脱争论。
要消除移动和其他对象,您必须直接从中初始化:
int main()
{
// std::vector<std::string> v;
//...
// The result would be constructed directly into v
std::vector<std::string> v = createAndInsert();
//...
}
int main()
{
std::vector<std::string> v; // create empty vector of strings
//...
std::destroy_at(&v);
::new (&v) auto(createAndInsert()); // construct returned vector of strings into v
// Though this method has a lot of problems if `createAndInsert` throws
//...
}