昨天晚上,SISTSIST 的宋教授在 SISTSIST 一个官方研招群里分享了一个 BugBug,如下图:
代码如下:
一开始我觉得没问题啊,怎么会出现段错误呢?并且 newnew 怎么可能不是 newnew 一个 heapheap 对象?(后来得知教授的意思是 ssss 无法 newnew 到堆上让他保持)
之所以有这样的疑问,也是因为虽然我经常用 C++C++,但是多数都是用来做 OJOJ 题目,所以并不常用工程项目中所用到的一些用法,也就缺乏这方面的经验。
宋教授告诉我是因为 ObjectLifetimeObjectLifetime,可是我一下子并没有想明白为什么,于是尝试去还原一下 BugBug,如下是还原后的代码及编译情况:
在不加 staticstatic 的情况下,产生了段错误,不过直接原因并不像有的学长说的那样,是因为返回了 newnew 对象,这只是间接原因,真正的原因是 ssss,因为 ssss 是一个 std::istreamstd::istream 对象,不能拷贝只能引用,所以在 Reader(ss)Reader(ss) 里传递过去了 ssss 的引用,这也是我们题目中所说的返回局部对象的引用的 BugBug 之所在,不过为什么如此这般就是 BugBug 呢?
在这里我们需要简单说一些局部对象的生命周期(Lifetime)(Lifetime),我们在函数 make_reader()make_reader() 中声明的两个对象 s1s1 和 ssss 都是局部对象,在这个函数结束后,这两个局部对象的生命周期也就结束了,被销毁了。待到我们调用这个函数返回的 Reader∗Reader∗ 中的 ssss 引用时,很容易发现 ssss 本体都已经被销毁了,引用还有什么存在的意义呢,如果非要说他存在的意义,那就是造成段错误。由于局部对象是放在段里的,所以引用指向的也是段里,当段里的对象被销毁时,引用也就造成了段错误。
那么这种问题怎么解决呢?
根据刚才的分析是因为局部对象生命周期结束导致的,那么我们可以想办法改变他的生命周期,方法之一就是 staticstatic,这样他的生命周期就贯穿整个程序,也就不会出现段错误了。
不过个人感觉这样做欠妥,因为加上 staticstatic 的时候他只会在第一次调用时真正的执行,后续的调用时都会沿用上一次的状态,这样是否会造成混乱呢?
暂时没有想到更好的解决方案,欢迎大家指点。
返回局部对象的引用的 BugBug 我们可能已经讲得十分清楚了,指针同理。