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


      带着学生做课程设计。程序一大,课程中做过了小项目,练过了分解动作,一到合起来了,难免还是要乱了分寸。事实上,实战的功夫,就是这样出来的。(课程设计指导视频链接(第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中保存的是空业务。当用户password验证成功。会创建后者。自然业务信息也空。当运行完b.work();,会运行后者的析构函数,将这次业务后的业务信息保存在了文件里。文件内容不会是空。
      然而,当程序的运行离开main函数时,其局部的变量b(前者)也要析构,这时就是问题之所在,这个b中的业务信息是空的,文件打开重建后。没有要写入的信息,最后就是空文件了。


      所以,解决的办法。将两个Bank b;。不管前者或后者。去掉一个就可以。
      问题攻克了,再反思。前述的问题自然不该发生,但这里设计的缺陷也存在。

    在程序中直接将文件名称写定。而且写在构造函数和析构函数中,也就意味着该类的全部对象都用同一个文件(如同Person类中的每一个对象都用同一个碗吃饭,多家银行将数据存在一个文件里。太可怕了)。合理的做法是,採取某种机制,不同对象,使用不同的文件。
      当然。对于本文中的问题。就是不该定义两个 Bank b。

  • 相关阅读:
    Sqoop架构(四)
    为什么选择Sqoop?(三)
    Sqoop 是什么?(二)
    Sqoop 产生背景(一)
    Ambari是啥?主要是干啥的?
    Ambari架构及安装
    Hadoop Hive概念学习系列之HDFS、Hive、MySQL、Sqoop之间的数据导入导出(强烈建议去看)(十八)
    Effective C++ -- 构造析构赋值运算
    pcduino v2安装opencv2.4.8
    Struts2 拦截器具体配置过程
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5224467.html
Copyright © 2020-2023  润新知