bugprone-move-forwarding-reference¶
如果在转发引用上调用 std::move
,则会发出警告,例如
template <typename T>
void foo(T&& t) {
bar(std::move(t));
}
转发引用 通常应传递给 std::forward
而不是 std::move
, 这是建议的修复方法。
(转发引用是类型为推导的函数模板参数的右值引用。)
在此示例中,建议的修复方法是
bar(std::forward<T>(t));
背景¶
上面示例中的代码有时会以 T&&
无论为 T
推导出什么类型,最终始终为右值引用,因此不可能将左值传递给 foo()
的预期编写。但是,这不是真的。考虑以下示例
std::string s = "Hello, world";
foo(s);
此代码编译,并且在调用 foo()
后, s
处于不确定的状态,因为它已被移动。这对于 foo()
的调用者来说可能是令人惊讶的,因为在调用 foo()
时没有使用 std::move
。
这种行为的原因在于函数模板(例如 foo()
)上的模板参数推导特殊规则,即在接受类型为推导的函数模板参数的右值引用参数的函数模板上。(请参阅 C++11 标准中的 [temp.deduct.call]/3 节。)
如果在左值上调用 foo()
(如上面的示例),则 T
被推导出为左值引用。在示例中, T
被推导出为 std::string &
。因此,参数 t
的类型变为 std::string& &&
;根据引用折叠规则,这将折叠为 std::string&
。
这意味着 foo(s)
调用将 s
作为左值引用传递,并且 foo()
最终会移动 s
,从而将其置于不确定的状态。