Chinaunix首页 | 论坛 | 博客
  • 博客访问: 18671822
  • 博文数量: 7460
  • 博客积分: 10434
  • 博客等级: 上将
  • 技术积分: 78178
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-02 22:54
文章分类

全部博文(7460)

文章存档

2011年(1)

2009年(669)

2008年(6790)

分类: C/C++

2008-05-27 20:05:02

半天时间找到原因却仍未解决的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容器可安全使用?
* 不能实现深拷贝时,有没有办法解决浅拷贝问题?
阅读(270) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~