关于将临时对象作为const T&传递并绑定到类引用的副作用及相关未定义行为的技术问询
问题解答:
auto x = A("E")._s 是否会触发未定义行为? 答案是肯定存在,这条语句确实可能陷入未定义行为(UB),具体场景完全取决于类A的构造函数实现,咱们结合你给出的两种构造场景逐一分析:
场景1:类A通过左值引用接收构造参数
先看对应的代码实现:
struct A{ const std::string& _s; A(const std::string& s): _s(s){} }; int main(void){ auto x = A("E")._s; std::cout << x << '\n'; }
这里的问题根源和你提到的A a("E")案例完全一致:
- 字符串字面量
"E"会被隐式转换成一个临时的std::string对象,用来初始化构造函数的参数s。 - 这个临时
std::string的生命周期只持续到完整表达式结束——也就是A("E")._s这条语句执行完毕的瞬间。 auto会根据_s的类型推导为const std::string&,所以x会绑定到这个已经被销毁的临时对象上。后续访问x(比如std::cout那一行)就是在访问悬垂引用,属于标准定义的未定义行为。
注:如果显式让
x推导为值类型(比如auto x = static_cast<const std::string>(A("E")._s);),会在临时对象销毁前完成拷贝,这种情况就不会有问题,但默认的auto推导会保留引用属性,直接踩坑。
场景2:类A通过值传递接收构造参数
也就是你注释里的那个构造函数版本:
struct A{ const std::string& _s; A(const std::string s): _s(s){} // 按值传参 }; int main(void){ auto x = A("E")._s; std::cout << x << '\n'; }
这种情况编译器甚至会提前给你警告:提示你将引用成员绑定到了构造函数的临时参数s上。原因是:
- 按值传参时,
"E"会被拷贝到构造函数的局部参数s中,这个s是构造函数内的临时对象,生命周期只在构造函数执行期间。 - 当
A的临时对象创建完成后,s已经被销毁,_s直接变成悬垂引用。 - 此时不管
auto x推导成引用还是值,只要尝试访问x(哪怕是拷贝x的过程),都是在访问已经销毁的内存区域,同样属于未定义行为。
简单总结:只要类A的引用成员_s绑定的是临时对象(不管是构造函数参数引用的临时,还是构造函数值参数本身的临时),那么auto x = A("E")._s这条语句后续访问x时,必然会触发未定义行为。只有当_s绑定的是生命周期超过当前完整表达式的对象(比如全局变量、栈上持久存在的对象)时,这条语句才是安全的,但这已经超出了你给出的场景范围。
内容的提问来源于stack exchange,提问作者Pol
相关产品推荐
相关产品推荐

