C++通过临时对象自定义转换赋值给const引用的合法性及修复方案问询
问题根因
你遇到的是临时对象生命周期不匹配导致的悬空引用问题:const A& a = Foo(200, 100, 300); 语句中,Foo 临时对象在表达式结束后就会销毁,你定义的 operator const A&() 会返回 Foo 内部成员 a 的引用,Foo 销毁后这个引用自然就失效了。
解决方案
你可以根据自己的使用场景选下面任意一种方案:
方案1:删除引用转换函数,仅保留值转换(最推荐,适配所有场景)
直接删掉operator const A&() const,只保留operator A() const即可。
C++标准规定:值转换返回的临时对象绑定到const引用时,临时对象的生命周期会延长到和引用一致,不会出现悬空问题。修改后你原来的写法就可以正常运行:
// 修改后的Foo类转换函数只保留值转换 operator A() const { return a; } // 下面的写法合法,转换生成的A临时对象生命周期和a一致 const A& a = Foo(200, 100, 300);
这个方案也完全适配你现有的接收const A&/const B&的函数:传Foo临时对象给这些函数时,转换生成的临时A/B对象会在整个函数调用周期内有效,没有任何问题。
方案2:保留引用转换,禁止右值临时对象调用引用转换
如果你需要保留左值Foo的引用转换能力,可以给转换函数加左值引用限定,禁止右值临时Foo调用引用转换:
// 只有左值Foo对象可以调用引用转换 operator const A&() const & { return a; } // 右值临时Foo调用引用转换直接报错,从编译层面避免悬空 operator const A&() const && = delete;
修改后如果有人写const A& a = Foo(...)编译器会直接报错,强制使用者要么用值接收结果,要么先把Foo存为左值再取引用:
// 合法写法1:用值接收 const A a = Foo(200,100,300); // 合法写法2:Foo存为左值再取引用 Foo foo(200,100,300); const A& a = foo;
方案3:仅用作函数参数的场景不需要修改代码
如果你的Foo只会作为参数直接传给接收const A&的函数,不需要绑定到局部const引用,那现有代码不需要任何修改:
void printColor(const A& color) { std::cout << color.GetR() << color.GetG() << color.GetB() << std::endl; } // 完全合法,Foo临时对象会在函数调用结束后才销毁 printColor(Foo(200, 100, 300));
这种场景下引用不会悬空,可以正常运行。
内容的提问来源于stack exchange,提问作者sivan
相关产品推荐
相关产品推荐

