找出诡异的Bug:数据怎么存不进去

原创 2015年07月11日 09:41:19

  带着学生做课程设计。程序一大,课程中做过了小项目,练过了分解动作,一到合起来了,难免还是要乱了分寸。其实,实战的功夫,就是这样出来的。(课程设计指导视频链接(第36课时,3.18 银行系统开发),课程主页在链接,指导文档见链接,示例程序见链接)。
  话说,已经有两位做银行系统的同学和我说,“文件中写不进去数据。程序一退出,明明写进去了,结果却是空文件。”这不是一个小打击。
  做软件,找Bug,有些像打空气,使半天劲,人家就不理你。学计算机的人,练的就是这样的功夫,要学会自己创建线索,找出问题所在。
  话说,出问题的两位同学的程序,框架大体如下:

int main()
{
    Bank b;   //创建一个银行对象
    if (pass())    //用pass校验用户
    {
        Bank b;
        b.work();   //完成各种业务
    }
    return 0;
}

class Bank
{
    ……
}

Bank::Bank()
{
    ifstream infile("account.dat",ios::in);
    if(!infile)
    {
        cerr<<"open error!"<<endl;
        exit(1);
    }
    //下面的代码,将之前发生过的业务数据从文件读入银行对象

    infile.close();
}

Bank::~Bank()
{
    ofstream outfile("account.dat",ios::out);
    if(!outfile)    //测试文件打开操作是否成功,不成功则提示后退出。
    {
        cerr<<"open error!"<<endl;
        exit(1);
    }
    //下面的代码,将银行对象中的业务数据写入文件

    outfile.close();
    delete p;
}

  因为数据要在文件里存储,所以,可选的方案是,在构造函数中读文件,在析构函数中写文件。上面的程序就是照这种思路设计的。
  然而,程序退出后,文件就是空的。
  老贺看了也纳闷,写文件的语句中规中矩,然而就是不对。
  仔细审查析构函数中文件的打开方式ios::out,似乎有嫌疑,但排除了。在实际运行的系统中,ios::out的方式不常用,因为这样一打开,也就意味着存在的文件也要重建,用ios::app的更多。
  可是,在这个由大一学生实施的设计中,简化的方案是,将所有的数据读入内存,操作针对内存中的数据,而最后,就是要重建文件,将内存中的全部数据重写一遍。
  几百行的程序,就不可以用眼睛盯着找问题了。单步跟踪,对这样的程序,如果问题具体在哪儿都不清楚,也不是一个好办法。
  析构函数中写文件的部分最可疑。我在析构函数~Bank中加了一句“cout<<"in destructor."<<endl;”。结果发现,最后的,析构函数执行了两次。
  然后,在main函数的return 0;前加了一句“cout<<"end of main"<<endl;”,发现输出的信息是:

in destructor.
end of main
in destructor.

  再看main函数,真相大白了。问题出在main函数中:Bank b出现了两次:一个是属于main函数的局部对象b(前者,第3行),另一个的作用范围,只在if语句的一对花括号内的对象b(后者,第6行)。
 程序初次执行,文件为空,前者执行构造函数,b中保存的是空业务。当用户密码验证成功,会创建后者,自然业务信息也空。当执行完b.work();,会执行后者的析构函数,将这次业务后的业务信息保存在了文件中。文件内容不会是空。
  然而,当程序的执行离开main函数时,其局部的变量b(前者)也要析构,这时就是问题之所在,这个b中的业务信息是空的,文件打开重建后,没有要写入的信息,最后就是空文件了。
  所以,解决的办法,将两个Bank b;,无论前者或后者,去掉一个即可。
  问题解决了,再反思。前述的问题自然不该发生,但这里设计的缺陷也存在。在程序中直接将文件名写定,并且写在构造函数和析构函数中,也就意味着该类的所有对象都用同一个文件(如同Person类中的每个对象都用同一个碗吃饭,多家银行将数据存在一个文件中,太可怕了)。合理的做法是,采取某种机制,不同对象,使用不同的文件。
  当然,对于本文中的问题,就是不该定义两个 Bank b。

版权声明:本文为博主原创文章,未经博主允许不得转载。

Hibernate 中save方法运行成功之后却没有保存进数据库的原因

刚刚使用myeclipse的Hibernate 反向工程生成的dao文件的save方法不能入库1.首先很多时候我们把id设置为自动增长的,而反向工程生成的类中并没有设置申明该字段为自增,可以对这个字段...
  • snoopy93
  • snoopy93
  • 2011年03月15日 21:30
  • 4644

程序猿,你调试过的最难 Bug 是?

调试 Bug 是每个程序员工作中必须品。在 Quora 上有一个和 Bug 相关的热门问答帖:《What’s the hardest bug you’ve debugged? | 你调试过的最难 Bu...
  • zz2043191420
  • zz2043191420
  • 2015年08月20日 09:50
  • 1403

bug调试的教程

MyEclipse下的Debug调试 http://hi.baidu.com/stresume/blog/item/df904fee0a70adfcb2fb9549.html 首先以deb...
  • awpshoot
  • awpshoot
  • 2015年09月18日 17:28
  • 255

VS调试Bug记录

这里记下我调试遇到的bug及解决方案,想到哪些记哪些。 1、wincrtl1.cpp 80错误 解决方案: 调试后发现定位到void CButton::DrawItem(LPDRAWITEMS...
  • yoyo18520
  • yoyo18520
  • 2017年05月01日 12:04
  • 382

ACM-BFS之诡异的楼梯——hdu1180

bfs 广度优先搜索 hdu1180
  • lx417147512
  • lx417147512
  • 2014年02月25日 13:38
  • 1281

hdu1180诡异的楼梯(bfs)

这道题的意思是哈利波特要从S走到T,中间有那种会改变方向的楼梯,经过楼梯的话一共只用一秒,但是可能会存在有特殊的楼梯会一秒改变一次方向,也就是说可能会等一秒,不会有两个楼梯连续挨着,还有很重要的一点就...
  • zcmartin2014214283
  • zcmartin2014214283
  • 2016年10月02日 15:49
  • 240

一个诡异的bug

这两天总是被各种该死的bug 所困扰,蛮简单一个事情混在一个不大不小的工程里面确实不好找。 所以看来做大系统的时候规范和日志就显得十分重要。这个bug足足折腾了两天时间, 哎..... ...
  • suifeng50
  • suifeng50
  • 2015年11月26日 17:26
  • 506

webbug 很诡异的bug

今天遇到一个很诡异的bug,bug的名称跟原因不是一回事,所以这里就不再写bug的名称 记得看《亮剑》的时候,上面有句话“良将用病若良医用药,病万变,药亦万变”。亮剑上还有话就是:逢敌必亮剑 ...
  • longyuan20102011
  • longyuan20102011
  • 2013年07月09日 17:06
  • 495

HDOJ/HDU 1180 诡异的楼梯(经典BFS-详解)

Problem Description Hogwarts正式开学以后,Harry发现在Hogwarts里,某些楼梯并不是静止不动的,相反,他们每隔一分钟就变动一次方向. 比如下面的例子里,一开始楼...
  • qq_26525215
  • qq_26525215
  • 2016年07月10日 16:25
  • 7555

常见bug调试方法

常见bug调试方法 此处为大量Copy!不喜请喷! The software doesn't do something that the product specification...
  • yst19910702
  • yst19910702
  • 2016年06月03日 09:45
  • 3478
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:找出诡异的Bug:数据怎么存不进去
举报原因:
原因补充:

(最多只允许输入30个字)