const std::function&作为类成员时的异常运行行为疑问
问题原因分析
你的代码的核心问题是类成员引用绑定临时对象导致的悬垂引用,触发了C++未定义行为,具体拆解如下:
- 首先
const Fn& fn_ = nullptr;这行初始化逻辑不符合引用的使用规则:C++的左值引用不能直接绑定nullptr,此处编译器会自动触发隐式类型转换:- 用
nullptr作为参数调用std::function的nullptr_t构造函数,生成一个临时的Fn对象,这个临时对象本身是空状态,正常判断的话会返回false - 把
fn_这个const左值引用绑定到这个临时对象上
- 用
- 其次C++的「临时对象绑定到const引用生命周期延长规则」不适用于类成员引用的场景:这个临时
Fn对象的生命周期仅持续到Foo类构造函数执行结束,构造完成后临时对象就被销毁,fn_直接变成悬垂引用 - 最后你在
bar()函数中执行if(fn_)判断时,本质是访问已经被销毁的对象的内存空间,属于未定义行为,gcc环境下刚好读到的残留内存值被判定为非空,所以输出了1,换成其他编译器或者编译参数完全可能出现其他结果(比如输出2、程序崩溃都是正常的)
修复方案
如果要实现预期输出,最简单的修改是不要用引用类型存std::function,直接存储实例即可:
private: const Fn fn_ = nullptr;
修改后fn_是独立的std::function实例,用nullptr初始化后确实为空,if(fn_)判断会返回false,稳定输出2。
如果你一定要用引用作为成员变量,必须确保引用绑定的对象生命周期长于Foo类实例的生命周期,不能用临时对象绑定。
内容的提问来源于stack exchange,提问作者Ruotong Jia
相关产品推荐
相关产品推荐

