找出诡异的Bug:数据怎么存不进去[通俗易懂]

找出诡异的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。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/115866.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • bypasswaf之盲注

    0x00前言前面讲到了联合查询如何过waf,那么今天给大家来讲讲盲注怎么去,bypasswaf。这里还是以xx狗为例。0x01与waf的对抗我们来试试常规的注入思路。'单引号不

    2021年12月11日
    57
  • gbk和utf8的区别元尊_gb2312和utf8的区别

    gbk和utf8的区别元尊_gb2312和utf8的区别我们这里将以最简单最容易理解的方式来描述GBK和UTF8的区别,以及它们分别是什么。GBK编码:是指中国的中文字符,其它它包含了简体中文与繁体中文字符,另外还有一种字符“gb2312”,这种字符仅能存储简体中文字符。UTF-8编码:它是一种全国家通过的一种编码,如果你的网站涉及到多个国家的语言,那么建议你选择UTF-8编码。GBK和UTF8有什么区别?UTF8编码格式很强大,支持所有国家的语言,正是

    2025年8月14日
    3
  • wpf listview 分组_JAVA排序

    wpf listview 分组_JAVA排序网上很多方法,但是内容包含太全面,代码看上去很复杂,其实其中有很多是控制UI的,此种方法一行代码自动解决排序问题,另外,wpf的listview和winform的listview细节差别还是很多的。在WPF中ListView的排序最基本的原理很简单就一句话ListViewControl.Items.SortDescriptions.Add(newSortDescription(“name”,…

    2022年10月3日
    1
  • 《架构之美》笔记_印象笔记如何创建目录

    《架构之美》笔记_印象笔记如何创建目录美是创造矛盾并解决矛盾。架构的多关注点(例如业务逻辑、系统扩展性、持久、并发)和简洁性就是一种矛盾,美丽的架构能解决这种矛盾,使人内心产生愉悦;随着关注点的增加,架构也在不断演进;术:分层、组件化、服务化、标准化、缓存、分离、队列、复制、冗余、代理;道:如何恰到好处地使用术,例如顿悟变化的道理、博弈中寻找平衡、相对与绝对的奥秘、开放的心态;爱因斯坦说:『让它尽可能简单,但不要过于简单』,美

    2025年6月10日
    5
  • MySql 字段类型对应 Java 实体类型

    MySql 字段类型对应 Java 实体类型MySql 字段类型对应 Java 实体类型前言 CopyMySQLCon J 对于 MySql 数据类型和 Java 数据类型之间的转换是很灵活的 一般来讲 任何 MySql 数据类型都可以被转换为一个 java lang String 任何 MySql 数字类型都可以被转换为任何一种 Java 数字类型 当然这样也可能出一些四舍五入 溢出 精度丢失之类的问题 Java 基础类型与包装类型 Copya 如果数据库字段是允许为空的 使用包

    2025年10月15日
    3
  • Hadoop入门——初识Hadoop

    Hadoop入门——初识Hadoop推荐一个微信商城,扫码即可购买,性价比超高,程序员必备店主就是博主,有任何问题可随时通过商城内的微信与博主取得联系一.hadoop是什么Hadoop被公认是一套行业大数据标准开源软件,在分布式环境下提供了海量数据的处理能力。几乎所有主流厂商都围绕Hadoop开发工具、开源软件、商业化工具和技术服务。今年大型IT公司,如EMC、Microsoft、Intel、Teradata、…

    2022年6月2日
    34

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号