天天看點

找出詭異的Bug:資料怎麼存不進去

  話說,已經有兩位做銀行系統的同學和我說,“檔案中寫不進去資料。程式一退出,明明寫進去了,結果卻是空檔案。”這不是一個小打擊。

  做軟體,找bug,有些像打空氣,使半天勁,人家就不理你。學計算機的人,練的就是這樣的功夫,要學會自己建立線索,找出問題所在。

  話說,出問題的兩位同學的程式,架構大體如下:

  因為資料要在檔案裡存儲,是以,可選的方案是,在構造函數中讀檔案,在析構函數中寫檔案。上面的程式就是照這種思路設計的。

  然而,程式退出後,檔案就是空的。

  老賀看了也納悶,寫檔案的語句中規中矩,然而就是不對。

  仔細審查析構函數中檔案的打開方式ios::out,似乎有嫌疑,但排除了。在實際運作的系統中,ios::out的方式不常用,因為這樣一打開,也就意味着存在的檔案也要重建,用ios::app的更多。

  可是,在這個由大一學生實施的設計中,簡化的方案是,将所有的資料讀入記憶體,操作針對記憶體中的資料,而最後,就是要重建檔案,将記憶體中的全部資料重寫一遍。

  幾百行的程式,就不可以用眼睛盯着找問題了。單步跟蹤,對這樣的程式,如果問題具體在哪兒都不清楚,也不是一個好辦法。

  析構函數中寫檔案的部分最可疑。我在析構函數~bank中加了一句<code>“cout&lt;&lt;"in destructor."&lt;&lt;endl;”</code>。結果發現,最後的,析構函數執行了兩次。

  然後,在main函數的return 0;前加了一句<code>“cout&lt;&lt;"end of main"&lt;&lt;endl;”</code>,發現輸出的資訊是:

in destructor. end of main

  再看main函數,真相大白了。問題出在main函數中:bank b出現了兩次:一個是屬于main函數的局部對象b(前者,第3行),另一個的作用範圍,隻在if語句的一對花括号内的對象b(後者,第6行)。

 程式初次執行,檔案為空,前者執行構造函數,b中儲存的是空業務。當使用者密碼驗證成功,會建立後者,自然業務資訊也空。當執行完b.work();,會執行後者的析構函數,将這次業務後的業務資訊儲存在了檔案中。檔案内容不會是空。

  然而,當程式的執行離開main函數時,其局部的變量b(前者)也要析構,這時就是問題之所在,這個b中的業務資訊是空的,檔案打開重建後,沒有要寫入的資訊,最後就是空檔案了。

  是以,解決的辦法,将兩個bank b;,無論前者或後者,去掉一個即可。

  問題解決了,再反思。前述的問題自然不該發生,但這裡設計的缺陷也存在。在程式中直接将檔案名寫定,并且寫在構造函數和析構函數中,也就意味着該類的所有對象都用同一個檔案(如同person類中的每個對象都用同一個碗吃飯,多家銀行将資料存在一個檔案中,太可怕了)。合理的做法是,采取某種機制,不同對象,使用不同的檔案。

  當然,對于本文中的問題,就是不該定義兩個 bank b。