科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件半天时间找到原因却仍未解决的Bug

半天时间找到原因却仍未解决的Bug

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在一个巨大的数据文件作为输入时, 出现了一个assert断言错误. 花了半天时间跟踪代码, 费尽心思找到了错误的来源, 可是一时间也没有解决的办法, 只能打个临时补丁.

作者:金庆 来源:CSDN 2008年3月22日

关键字: C C++ 未解决 Bug Linux

  • 评论
  • 分享微博
  • 分享邮件
半天时间找到原因却仍未解决的Bug

在一个巨大的数据文件作为输入时, 出现了一个assert断言错误.
花了半天时间跟踪代码, 费尽心思找到了错误的来源,
可是一时间也没有解决的办法, 只能打个临时补丁.

类里面有个成员变量
    std::ofstream m_ofs;
   
在某个方法里面的断言警告:
    assert(!m_ofs);
       
流操作之后都有一个状态判断:
    if (!m_ofs)
    {
        log...
        m_ofs.close();
        return;
    }
为什么会有错误的流状态?

但是open()操作后判断失败没有关闭流.
    m_ofs.open(sPath);
    if (!m_of)
    {
        log...
        return;
    }

表面上看是ofstream::open()打开文件出错了.
open()出错时只写了一条日志, 没做处理.
这个ofstream对象m_ofs不是临时对象, 而是类内嵌对象.
下一次使用时, 发现m_ofs处于已打开状态, 而流状态是错误的,

以为open()失败后文件会处于关闭状态, 看来是错误的.
open()失败后加了一个close()试了试,还是有流错误。

open()为什么会出错? strerror(errno)显示"No error".
以为是errno没有正确指示错误, 再跟踪进入open()代码, 发现open()其实是成功了.
m_ofs是在open()之前就已经fail了(查看内部状态State=2, 即failbit位).

一定是上次close()后failbit并没有清除.
close()成功情况下, 会执行clear(), 但有可能close()失败.

添加clear()在所有close()之前.
可是failbit象是凭空出现, clear()并没有起作用.

回忆历史代码, 原来只有临时变量的流, 用完就自动关闭了.
而为了对付频繁的同一文件打开, 流对象改为了内部成员变量.
而流的宿主类间接地是另一个类的成员变量, 该类是某stl容器类的元素.

问题就在这里了, stl容器类会使用其元素类的拷贝构造函数来复制元素.
一定是ofstream通过这样的复制后产生了错误的状态.
而宿主类及其上层也没有提供拷贝构造函数, 只有默认的浅拷贝.
如果没有这个流, 这些类都是一些简单数据类, 完全可以使用默认的字节拷贝.

浅拷贝不行, 深拷贝不能, 结果是找到原因, 却不知如何修改.
只能暂时恢复为临时流变量.
不过最终还应该支持大量的文件打开关闭操作, 不知怎么办.

心得:
* 没有必要就不要保存一个流变量,使用临时变量可保证文件打开与关闭是成对的。
* stl容器最好只存放简单数据,可避免自定义拷贝构造函数。
如果元素类较复杂,应考虑使用指针,因为有可能今后的修改后使元素类更复杂。
* ofstream::close()可能不会清除错误状态,并可能置failbit,如未打开就关闭。
上面的clear()应加在close()之后。

问题:
* 如何添加单元测试,使得一个类保证为简单数据类,或保证stl容器可安全使用?
* 不能实现深拷贝时,有没有办法解决浅拷贝问题?
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章