何时在函数调用中使用 move
when to use move in function calls
我目前正在学习有关所有 c++11/14 功能的更多信息,想知道何时在函数调用中使用 std::move。
我知道我不应该在返回局部变量时使用它,因为这会破坏 Return 值优化,但我真的不明白在函数调用中转换为右值实际上有什么帮助。
当一个函数接受一个 右值引用 时,你必须提供一个 右值 (要么已经有一个 prvalue,或使用 std::move
创建一个 xvalue)。例如
void foo(std::string&& s);
std::string s;
foo(s); // Compile-time error
foo(std::move(s)); // OK
foo(std::string{}) // OK
当函数接受 值 时,您可以使用 std::move
移动构造函数参数而不是复制构造。例如
void bar(std::string s);
std::string s;
bar(s); // Copies into `s`
bar(std::move(s)); // Moves into `s`
当函数接受 转发引用 时,您可以使用 std::move
允许函数将对象进一步向下移动到调用堆栈中。例如
template <typename T>
void pipe(T&& x)
{
sink(std::forward<T>(x));
}
std::string s;
pipe(s); // `std::forward` will do nothing
pipe(std::move(s)); // `std::forward` will move
pipe(std::string{}); // `std::forward` will move
当您有一些实质性对象,并将其作为参数传递给函数(例如 API 或容器 emplace
操作)时,您将不再需要它在调用站点,因此您想要 转让所有权 ,而不是复制然后 "immediately" 丢失原始文件。那就是你移动它的时候了。
void StoreThing(std::vector<int> v);
int main()
{
std::vector<int> v{1,2,3,4,5,6/*,.....*/};
StoreThing(v);
}
// Copies `v` then lets it go out of scope. Pointless!
对比:
void StoreThing(std::vector<int> v);
int main()
{
std::vector<int> v{1,2,3,4,5,6/*,.....*/};
StoreThing(std::move(v));
}
// Better! We didn't need `v` in `main` any more...
如果未应用 RVO,则返回局部变量时会自动发生这种情况(请注意,自 C++17 以来,这样的 "optimisation" 是强制要求的,因此您说添加 "redundant" std::move
在那种情况下实际上是有害的)。
此外,如果您传递的是非常小的东西(尤其是非 class 不可能有移动构造函数的东西,更不用说有意义的东西了!),那么 std::move
也毫无意义!知道您正在传递给接受其参数 const
-ly 的函数;在这种情况下,由您决定是否要保存不会执行任何操作的 std::move
添加的源代码干扰:表面上它是明智的,但在模板中您可能不太确定。
我目前正在学习有关所有 c++11/14 功能的更多信息,想知道何时在函数调用中使用 std::move。
我知道我不应该在返回局部变量时使用它,因为这会破坏 Return 值优化,但我真的不明白在函数调用中转换为右值实际上有什么帮助。
当一个函数接受一个 右值引用 时,你必须提供一个 右值 (要么已经有一个 prvalue,或使用 std::move
创建一个 xvalue)。例如
void foo(std::string&& s);
std::string s;
foo(s); // Compile-time error
foo(std::move(s)); // OK
foo(std::string{}) // OK
当函数接受 值 时,您可以使用 std::move
移动构造函数参数而不是复制构造。例如
void bar(std::string s);
std::string s;
bar(s); // Copies into `s`
bar(std::move(s)); // Moves into `s`
当函数接受 转发引用 时,您可以使用 std::move
允许函数将对象进一步向下移动到调用堆栈中。例如
template <typename T>
void pipe(T&& x)
{
sink(std::forward<T>(x));
}
std::string s;
pipe(s); // `std::forward` will do nothing
pipe(std::move(s)); // `std::forward` will move
pipe(std::string{}); // `std::forward` will move
当您有一些实质性对象,并将其作为参数传递给函数(例如 API 或容器 emplace
操作)时,您将不再需要它在调用站点,因此您想要 转让所有权 ,而不是复制然后 "immediately" 丢失原始文件。那就是你移动它的时候了。
void StoreThing(std::vector<int> v);
int main()
{
std::vector<int> v{1,2,3,4,5,6/*,.....*/};
StoreThing(v);
}
// Copies `v` then lets it go out of scope. Pointless!
对比:
void StoreThing(std::vector<int> v);
int main()
{
std::vector<int> v{1,2,3,4,5,6/*,.....*/};
StoreThing(std::move(v));
}
// Better! We didn't need `v` in `main` any more...
如果未应用 RVO,则返回局部变量时会自动发生这种情况(请注意,自 C++17 以来,这样的 "optimisation" 是强制要求的,因此您说添加 "redundant" std::move
在那种情况下实际上是有害的)。
此外,如果您传递的是非常小的东西(尤其是非 class 不可能有移动构造函数的东西,更不用说有意义的东西了!),那么 std::move
也毫无意义!知道您正在传递给接受其参数 const
-ly 的函数;在这种情况下,由您决定是否要保存不会执行任何操作的 std::move
添加的源代码干扰:表面上它是明智的,但在模板中您可能不太确定。