为何从Lambda返回const引用会产生临时对象?成员返回const&转发触发警告原因
为什么Lambda转发const&会触发临时对象警告,而链式调用却没问题?
嘿,这个问题我之前也琢磨过,咱们一点点拆解清楚~
先明确编译器警告的本质
你遇到的returning address of local variable or temporary警告,核心是返回的引用指向了一个已经(或即将)销毁的临时对象,属于C++里的未定义行为(UB)。编译器能检测到这个风险,所以给你提了醒。
为什么链式调用看起来“正常工作”?
咱们拿一个具体的代码例子来说明,假设你的类结构是这样的:
class Bar { public: const std::string& get_str() const { return inner_str; } private: std::string inner_str = "test"; }; class Foo { public: Bar get_bar() const { return Bar{}; } // 返回临时Bar对象 };
当你写链式调用foo.get_bar().get_str()时,C++的生命周期规则会帮你延长临时Bar对象的生命周期——它会一直存活到整个表达式结束(比如这条语句执行完)。所以在调用get_str()的时候,临时Bar还活着,返回的引用指向的inner_str也是有效的,看起来就“正常工作”了。
为什么Lambda里转发就会触发警告?
再看Lambda的场景:
auto lambda = [](const Foo& foo) -> const std::string& { return foo.get_bar().get_str(); };
这里的问题出在临时对象的生命周期不会跨Lambda的边界:
- 在Lambda内部,
foo.get_bar()创建了一个临时Bar对象; - 调用
get_str()返回这个临时Bar内部inner_str的引用; - 当Lambda执行到
return语句结束后,临时Bar对象就被销毁了,它的成员inner_str自然也跟着没了; - 这时候Lambda返回的引用就变成了“悬空引用”,指向已经被回收的内存,这就是编译器警告的原因。
两者的核心区别
链式调用中,临时对象的生命周期是绑定到整个表达式的;而Lambda返回引用时,临时对象的生命周期只到Lambda函数执行完毕,返回的引用无法再绑定到外部的任何变量来延长临时对象的生命——因为临时对象是在Lambda内部创建的,外部根本看不到它,自然没法触发生命周期延长规则。
额外提醒
哪怕链式调用看起来正常,如果你把结果绑定到一个引用变量,比如:
const std::string& ref = foo.get_bar().get_str();
这时候临时Bar对象的生命周期会延长到ref的生命周期结束,这是合法的。但如果是Lambda返回的引用,你把它绑定到外部变量,那这个变量就是悬空的,绝对不能用。
内容的提问来源于stack exchange,提问作者yano
相关产品推荐
相关产品推荐

