簡體   English   中英

C ++中不穩定錯誤的最常見原因是什么?

[英]Most common reasons for unstable bugs in C++?

我目前正在開展一個大型項目,我花了大部分時間進行調試。 雖然調試是一個正常的過程,但是存在不穩定的錯誤,這些錯誤對於開發人員來說是最大的痛苦。 該程序不起作用,有時候......有時它確實如此,而且你無能為力。

可以對這些錯誤做些什么? 最常見的調試工具(交互式調試器,手表,日志消息)可能會導致您無處可去,因為該錯誤將消失...只是稍后再次出現。 這就是為什么我要求一些啟發式方法:這些錯誤最常見的原因是什么? 我們應該調查哪些可疑代碼來找到這樣的錯誤?

讓我開始列表:

  1. 使用未初始化的變量。 常見的印刷錯誤,如mMember = mMember;
  2. 線程同步。 有時它可能是運氣的問題;
  3. 使用非智能指針,取消引用無效指針;

還有什么?

IME許多項目的根本問題是開發人員使用C ++的低級功能,如手動內存管理,C風格的字符串處理等,即使它們很少需要(然后只能很好地封裝在類中)。 這會導致內存損壞,指針無效,緩沖區溢出,資源泄漏等等。 一直都是漂亮而干凈的高級構造。

多年來,我一直是大型(幾個MLoC)應用程序團隊的一員,應用程序不同部分的崩潰錯誤數量與這些部分中使用的編程風格很好地相關。 當被問到為什么他們不會改變他們的編程風格時,一些罪魁禍首回答說他們的風格通常會產生更多的表現。 (不僅這是錯誤的,這也是一個事實,客戶寧可擁有一個更穩定但速度更慢的程序而不是快速崩潰的程序。此外,他們的大多數代碼甚至不需要快速......)

至於多線程:我覺得在這里提供解決方案並不夠專業,但我認為Herb Sutter的Effective Concurrency專欄是一個非常值得一讀的主題。

編輯以解決評論中的討論

我沒有寫過“C風格的字符串處理不是更高效”。 (當然在這句話中有很多否定,但由於我覺得誤讀,我試着准確。)我所說的是高級構造通常不太高效: std::vector 通常不比手動慢做動態分配的C數組,因為它是一個動態分配的C數組。 當然,有些情況下根據特殊要求編碼的內容比任何通用解決方案都要好 - 但這並不一定意味着您將不得不求助於手動內存管理 這就是我寫這個的原因,如果這些事情是必要的,那么只能在類中進行良好的封裝。

但更重要的是:在大多數代碼中,差異並不重要。 一個按鈕在有人點擊它之后壓縮0.01秒或者0.05secs只是無關緊要,所以即使是因子5速度增益也與按鈕的代碼無關。 然而,代碼崩潰是否總是重要的。

總結我的論點:首先讓它正常工作。 最好使用久經考驗的現成構建模塊。 然后測量。 然后使用久經考驗的現成成語提高性能。

我實際上要發一個問題正好相反的問題 - 其他人發現,就像我一樣,你在使用C ++時幾乎沒有時間使用調試器嗎? 老實說,我記不清上次使用它了 - 它一定是六個月前的。

坦率地說,如果你把大部分時間花在調試器上,我認為你的基本編碼實踐存在一些問題。

比賽條件。

這些是在調試(或在問題跟蹤器中)出現時仍然讓我感到顫抖的少數事情之一。 調試固有的可怕,並且非常容易創建。 我的C ++軟件中三個最常見的錯誤原因是競爭條件,對未初始化內存的依賴以及對靜態構造函數順序的依賴。

如果你不知道競爭條件是什么,那么它們可能是你不穩定的原因;)

如果你真的處在一個已經破壞了壞代碼的位置,那么最好的計划可能是盡可能多地使用它(OS / lib級內存檢查,自動化測試,日志記錄,核心轉儲等)找到問題領域。 然后重寫代碼以做一些更確定的事情。 大多數錯誤來自人們大多數時間都在工作的事情,但如果你使用正確的工具和方法,C ++提供了更強的保證。

還沒有看到這個提到的:

  • 從沒有虛析構函數的類繼承。
  • 在通過內存寫回緩存行時從未緩存的內存中讀取(這是一個正確的混蛋)。
  • 緩沖區覆蓋
  • 堆棧溢出!

我可以想到的唯一3個...可以稍后編輯:)

  • 緩沖區溢出
  • 使用指針刪除對象
  • 返回無效引用或引用超出范圍對象
  • 未處理的例外
  • 資源泄漏(不僅是內存)
  • 無限遞歸

  • 動態庫版本不匹配

不是C ++問題,而是在C / C ++項目中看到的。

我必須處理的最棘手的問題是在我們的平台上啟動操作系統時導致異常崩潰時的初始化問題。 我們花了幾年才發現發生了什么。 在此之前,我們一夜之間運行系統,如果它沒有崩潰,那么它通常是正常的。 幸運的是,操作系統不再銷售。

在分配之前或解除分配之后使用的地址和內存,分段錯誤,數組跳出,偏移,線程鎖定,無法理解的運算符重載,內聯匯編,void out和一般情況下需要返回值的void會使math.h函數值得一看,因為所有的數學運算都是值得的.h函數都有工作參數和返回值,與其他庫過度空,空虛測試,空,空和空隙相比。 我推薦的4個一般約定是返回值,參數,三元選擇和可逆變化。 要避免的錯誤是向量(使用數組而不是)使用空參數進行void,並且在我的主觀意見中,我避免使用switch語句來支持更易理解或可讀的if ifif或更抽象的“is”。

與腳本和解釋相比,C ++也具有相當糟糕的前向兼容性,嘗試使用十年前的Java,它在以后的vm中仍然保持不變且安全。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM