昨天晚上, SIST S I S T 的宋教授在 SIST S I S T 一个官方研招群里分享了一个 Bug B u g ,如下图:

代码如下:

一开始我觉得没问题啊,怎么会出现段错误呢?并且 new n e w 怎么可能不是 new n e w 一个 heap h e a p 对象?(后来得知教授的意思是 ss s s 无法 new n e w 到堆上让他保持)

之所以有这样的疑问,也是因为虽然我经常用 C++ C + + ,但是多数都是用来做 OJ O J 题目,所以并不常用工程项目中所用到的一些用法,也就缺乏这方面的经验。

宋教授告诉我是因为 ObjectLifetime O b j e c t L i f e t i m e ,可是我一下子并没有想明白为什么,于是尝试去还原一下 Bug B u g ,如下是还原后的代码及编译情况:


在不加 static s t a t i c 的情况下,产生了段错误,不过直接原因并不像有的学长说的那样,是因为返回了 new n e w 对象,这只是间接原因,真正的原因是 ss s s ,因为 ss s s 是一个 std::istream s t d :: i s t r e a m 对象,不能拷贝只能引用,所以在 Reader(ss) R e a d e r ( s s ) 里传递过去了 ss s s 的引用,这也是我们题目中所说的返回局部对象的引用的 Bug B u g 之所在,不过为什么如此这般就是 Bug B u g 呢?

在这里我们需要简单说一些局部对象的生命周期 (Lifetime) ( L i f e t i m e ) ,我们在函数 make_reader() m a k e _ r e a d e r ( ) 中声明的两个对象 s1 s 1 ss s s 都是局部对象,在这个函数结束后,这两个局部对象的生命周期也就结束了,被销毁了。待到我们调用这个函数返回的 Reader R e a d e r ∗ 中的 ss s s 引用时,很容易发现 ss s s 本体都已经被销毁了,引用还有什么存在的意义呢,如果非要说他存在的意义,那就是造成段错误。由于局部对象是放在段里的,所以引用指向的也是段里,当段里的对象被销毁时,引用也就造成了段错误。

那么这种问题怎么解决呢?

根据刚才的分析是因为局部对象生命周期结束导致的,那么我们可以想办法改变他的生命周期,方法之一就是 static s t a t i c ,这样他的生命周期就贯穿整个程序,也就不会出现段错误了。

不过个人感觉这样做欠妥,因为加上 static s t a t i c 的时候他只会在第一次调用时真正的执行,后续的调用时都会沿用上一次的状态,这样是否会造成混乱呢?

暂时没有想到更好的解决方案,欢迎大家指点。

返回局部对象的引用的 Bug B u g 我们可能已经讲得十分清楚了,指针同理。