C++开启编译优化选项后返回值异常问题排查
问题诊断
这不是编译器或STL的bug,你的代码存在明确的未定义行为,核心问题出在默认getter的lambda返回值推导错误:
- 你定义的
getType是返回const T&的函数类型,但默认构造时传入的lambda[this](){ return internal; }没有显式指定返回类型,C++14及更早标准下,无尾置返回类型的lambda会通过auto规则推导返回值,此处会推导为按值返回T(即返回internal的临时拷贝)。 - 当这个按值返回的lambda被包装进
std::function<const T&()>时,返回的临时值会绑定到const T&,但临时对象的生命周期仅持续到get()调用结束,之后你通过operator const T&()拿到的是已经销毁的对象的悬垂引用,读取悬垂引用就会读到栈上的随机垃圾值——这就是你看到输出数字每次运行都变的原因。 - O0优化级别下编译器不会主动复用/清理栈内存,临时值所在的栈位置没有被覆写,所以刚好能输出正确的12;开更高优化等级后栈空间被复用,就会读到随机值。VS的Debug模式默认是类似O0的无优化配置,所以看起来运行正常,切到Release模式同样会触发异常。
另外你的代码还有两个潜在问题:
- 只接收单个getter或单个setter的构造函数没有初始化另一个
std::function成员,也没有初始化internal成员,一旦调用到未初始化的set/get就会触发程序崩溃。 - 赋值运算符
operator=的参数是T& value,只能绑定左值,无法接收右值(比如字面量、临时对象),不符合常规赋值语义。
修复后的可运行代码
#include <functional> #include <iostream> template<typename T> class Property { private: using getType = std::function<const T&(void)>; using setType = std::function<void(const T&)>; T internal{}; // 给默认初始值,避免未初始化 getType get; setType set; public: Property(const T &value) : internal{value}, get{[this] () -> const T& { return internal; }}, // 显式指定返回引用,避免按值返回生成临时对象 set{[this](const T& value) { internal = value; }} {} Property(getType fnc) : get(fnc) { } Property(getType fncGet, setType fncSet) : get(fncGet), set(fncSet) { } Property(setType fnc) : set(fnc) { } Property(setType fncSet, getType fncGet) : get(fncGet), set(fncSet) { } // 参数改为const引用,支持绑定右值 Property<T> &operator=(const T& value) { set(value); return *this; } operator const T&() const { return get(); } }; int main(void) { Property<int> hey(12); std::cout << hey << std::endl; return hey; }
修复后所有优化级别、所有合规C++编译器下都能稳定输出12。
内容的提问来源于stack exchange,提问作者Az Kalaak
相关产品推荐
相关产品推荐

