爲什麼這是一種常見的做法,讓assert
宏只在調試配置中才有用?如果它存在測試不變量和檢測編碼錯誤,那麼繼續前進並在生產軟件中做同樣的繁榮是不是更容易?爲什麼斷言宏僅用於調試版本
我有一些S60背景,並存在__ASSERT_ALWAYS
和__ASSERT_DEBUG
,其中後者相當於assert
。
爲什麼這是一種常見的做法,讓assert
宏只在調試配置中才有用?如果它存在測試不變量和檢測編碼錯誤,那麼繼續前進並在生產軟件中做同樣的繁榮是不是更容易?爲什麼斷言宏僅用於調試版本
我有一些S60背景,並存在__ASSERT_ALWAYS
和__ASSERT_DEBUG
,其中後者相當於assert
。
檢查斷言成本。您可能不想在最終產品中存在額外的操作。如果斷言總是在起作用,那麼人們會開始使用它們來減少「不殺性能」。並相信我,有一個很多人誰認爲額外的檢查性能殺並會避免它。這些人實際上不得不使用斷言更多!
更重要的原因是,如果失敗,assert
將會中止您的程序。對於最終用戶來說沒有任何用處。如果你希望你的程序實際上終止一條消息或做一些有用的事情,你將不得不編寫自己的斷言。在這種情況下,您當然也可以選擇將其保持在發佈模式。
最後,斷言有助於您發現錯誤,特別是隱藏的錯誤,但在執行軟件時,它們可能實際上不會發生。想象一下下面的代碼:
struct X
{
// other stuff
int stage;
};
X x;
... do some stuff
assert(x.stage == STAGE_2);
x.stage = STAGE_3; // go to next stage
... do more stuff
在這樣的例子,你的邏輯說x
應該在STAGE_2
。如果不是,這是一個錯誤。但是,如果您刪除斷言,修復x.stage
並繼續前進,則希望錯誤不是那麼嚴重。在這種情況下,最終用戶實際上可以繼續工作而不會注意到這一點。如果您還將assert
保持在發佈模式,則會強制該人退出一個沒有任何明顯效果的錯誤。
實際上,您會隨時獲得軟件的更新,他們聲稱他們已經修復了錯誤。其中的一些,確實是assert
會發現的錯誤。然而,作爲最終用戶的你沒有任何問題,並且真的很開心你不會因爲那些assert
而被打斷,是不是?
assert
有效,除非您明確關閉它。有(通常)沒有 的理由關閉它,即使在「發佈」版本中,我發佈的大多數 已發佈的代碼都有assert
活動。
關閉它的主要原因是性能。在這種情況下,你 關閉它非常局部,在函數裏的表現 關鍵的,喜歡的東西:
#ifdef TURNOFFCRITICALASSERTS
#define NDEBUG
#include <assert.h>
#endif
// Function with critical code here...
#undef NDEBUG
#include <assert.h>
這是C標準委員會設計assert
的方式來使用。 通常,您不應該在本地定義NDEBUG
,像這樣。
我認爲這是一種文化的東西。贊成在生產代碼中刪除這種檢查的參數如下所示:
如下
就我個人而言,我發佈的軟件完全按照測試,斷言和所有軟件構建。但是,在很大程度上取決於你的客戶羣,以及如何你希望計劃發佈...
這篇文章值得一讀: - http://www.martinfowler.com/ieeeSoftware/failFast.pdf
但是當你部署軟件向客戶介紹什麼?我們不要 想要應用程序崩潰,只是因爲 配置文件中存在拼寫錯誤。對此恐懼的一種反應是禁用該領域的斷言 。
不要那樣做!請記住, 客戶網站發生的錯誤通過了您的測試過程。你可能 有麻煩重現它。這些錯誤是最難找到的,並且解釋問題的恰當地斷言可以爲您節省數天的時間。其他
一兩件事 - 在C++中,使用BOOST_ASSERT你可以將它扔在斷言失敗,這使得操作和更加有用斷言失敗可能恢復的異常。我們將此與MadExcept結合使用,以便該字段中的任何斷言失敗都可以輕鬆地由用戶發佈到我們的錯誤跟蹤器中,並提供完整的調用堆棧,截圖,whathaveyou。
不幸的是,在一個資本主義鯊魚的嚴酷世界中,幾乎沒有可重複的錯誤值得付出努力 – 2012-08-02 13:45:20
@RomanSaveljev - 我不同意:一個bug的商業影響可能與複製的容易程度完全無關。 – Roddy 2012-08-02 15:03:35
階段1:啓動車,階段2:檢查沒有人在路上,階段3:開車! - 所以如果我們跳過第二階段,沒問題? ;-)我明白你說的是什麼,但總的來說,不管斷言失敗後繼續是不是個好主意。 – Roddy 2012-08-02 15:08:53
@roddy,我認爲我們對於應該聲稱的內容有不同的看法。例如,'malloc'的輸出不是我會斷言的,但是確保我在AVL樹上的左旋操作不會使樹不平衡是我會用'assert'做的事情。不同之處在於第一個是應該處理的錯誤,否則就會發生不好的事情,第二個錯誤會造成性能問題。 – Shahbaz 2012-08-02 15:15:04
我同意 - 您的AVL樹是一個很好的例子,因爲驗證餘額可能是一個相對較慢的操作。我寧願看到malloc調用上的assert()比根本沒有檢查(儘管大多數應用程序沒有處理malloc失敗的有用方法)。當然,在C++'new'中,失敗會拋出... – Roddy 2012-08-02 15:23:06