CppCoreGuidelines F.45 不要返回 T&&
26 June 2022
F.45: Don’t return a T&&
理由
返回T&&
意味着返回已经销毁的临时对象。&&
就好比是吸附临时对象的磁铁。
例子
当你返回一个右值引用时,它的作用域范围在返回语句前已经结束了!
auto&& x = max(0, 1); // OK, so far foo(x); // Undefined behavior
这种用法经常导致 bug,编译器也会报错。函数开发人员应该避免这种陷阱。
安全生命周期开发要求及时发现这种问题。
例子
临时返回的右值引用,可以再次转交给调用的函数。但是不能向上返回给上一层函数内使用。对于引用或完美传递(perfect forwarding)方式传入的参数,又要返回值的,可以用 auto
推演返回类型(注意不是auto&&
)
假设 F
通过值返回:
// -*- compile-command: "g++ -std=c++20 code.cpp && ./a"; -*- #include <iostream> #include <gsl/gsl> using namespace std; using namespace gsl; template<class F> auto&& wrapper(F f) { cout << typeid(f).name(); // or whatever instrumentation return f(); // BAD: returns a reference to a temporary } int func() { return 100; } int main() { wrapper(func); // no way to get return value return 0; }
以下写法更好一些:
// -*- compile-command: "g++ -std=c++20 code.cpp && ./a"; -*- #include <iostream> #include <gsl/gsl> using namespace std; using namespace gsl; template<class F> auto wrapper(F f) { cout << typeid(f).name() << endl; // or whatever instrumentation return f(); // OK } int func() { return 100; } int main() { cout << wrapper(func); return 0; }
PFivE 100
例外
std::move
与std::forward
确实返回&&
,不过只是一次类型转换,用于在临时对象还没有被销毁前,将其引用传递出去。
强化
- 除了
std::move
与std::forward
之外,返回&&
的都要标记警告。