raf*_*foo 5 c++ move-semantics
我读过其他一些文章,这些文章move是不必要的,甚至对 NRVO 等机制进行了去优化。但在大多数情况下,这是关于当地领域的。
考虑这个例子:
\n\nstd::move在这种情况下,使用on是否合适return?\n具体来说,这些代码段是否等效?\n第二个更“通用”,让用户决定是否应该移动结果,第一个更严格\xe2\x80\x94 任何调用都会消耗结果。
\n// Option 1\n\n#include <utility>\n\ntemplate<typename T>\nclass TemporaryResultHolder\n{\npublic:\n void doTask() { result = T(); }\n\n T getResult() { return std::move(result); }\n // Or return T&& ?\n\nprivate:\n T result;\n};\n\nint main() {\n TemporaryResultHolder<int> holder;\n holder.doTask();\n int res = holder.getResult();\n\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n// Option 2\n\n#include <utility>\n\ntemplate<typename T>\nclass TemporaryResultHolder\n{\npublic:\n void doTask() { result = T(); }\n\n T getResult() { return result; }\n\nprivate:\n T result;\n};\n\nint main() {\n TemporaryResultHolder<int> holder;\n holder.doTask();\n int res = std::move(holder.getResult());\n\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n
是的,std::move(result)在这里是合适的,只要意图正是这样:从对象中“窃取”值并将其所有权传递给调用范围。
不过,我建议:
重命名该函数takeResult(),以显示它正在做什么。
或者使用 来限定函数本身&&,以增加安全性:那么只有当通过右值引用对象本身时才能使用此函数
T getResult() && { return std::move(result); }
// ...
holder.doTask();
int res = std::move(holder).getResult();
Run Code Online (Sandbox Code Playgroud)
如果你要返回一个带有自动存储的对象,那么你永远不应该返回 with std::move,因为前者在最好的情况下更快,在最坏的情况下相等。
我在其他一些帖子中读到,这是不必要的,甚至会去优化 NRVO 等机制。
这就是原因。然而,这不适用于问题中的函数,因为它不返回具有自动存储的对象,而是返回成员变量。NRVO 不能应用于成员变量,也不能隐式移动返回值。
因此,在您的示例中,return std::move(result);进行移动并return result;进行复制。如果函数的目的是从成员中移动,则应使用 move;如果函数的目的是复制成员,则应使用 copy。但请注意,从非右值限定的函数中移动成员是非常非常规的设计,我建议避免这样做,除非您有充分的理由这样做。另请注意,复制版本可以是 const 限定的,这将使其更普遍有用。
PS 对于int示例中使用的,这些区别是无关紧要的。移动与应对仅与非平凡的可复制/可移动类型相关。