2013-07-25 29 views
0

今天我發現我的一些斷言功能仍然存在,並在發佈版本中調用。這是我的斷言函數的一個例子。寫調試構建只斷言功能忽略副作用

bool const isDebugMode() 
{ 
    return false; // Will be controlled by preprocessor flag. 
} 
void assertWithReason(bool const condition, std::string const reason = "") 
{ 
    if (isDebugMode() and not condition) 
    { 
     abort(); 
    } 
} 

我認爲條件表達式中的一些副作用是防止消除斷言調用。

例如,

assertWithReason(glGetError() == GL_NO_ERROR); 

我預計這種說法呼叫被淘汰,但事實並非如此。因爲它在檢查調試構建之前正在執行。

我不確定C++如何處理這種情況,但是由於C++是非常嚴格的語言,它似乎不會被除去,除非我把一些特殊的標誌。無論如何,我有意將這些斷言寫入發佈版本中去除。

是否可以編寫一個函數,當然是在C++版本中刪除? 當然,我可以使用預處理器宏,但我想盡可能避免使用預處理器宏。

我使用的是Clang,而編譯器的特定擴展(如GCC屬性)也很好。

+0

爲什麼你主張的呼叫被「淘汰」?這仍然是被稱爲正常功能,而且表達用於第一個參數總是在函數被實際調用之前計算的,有一個原因主要是由預處理器宏來處理,因爲它允許你繞過普通的「函數調用之前的求值參數」規則 –

+0

在這種特殊情況下, t認爲編譯器應該消除這個調用 - 因爲'glGetError'有副作用 - 它會重置錯誤狀態 –

+0

注意:你對'assertWithReason'的調用實際上是inc orrect - 你錯過了原因。在Mats的答案中使用宏和字符串化就是IMO的最佳方法。 – Useless

回答

1

在C++ 11中,您可以使用lambda表達式。可能持續的傳播會使得is_debug永遠不會被消除,即使是這樣,lambda也不會被調用。

class Debug { enum { is_debug = 1; } }; 

template <class F> 
void assert(F f) { 
    if (is_debug && !f()) abort(); 
} 

{ 
    int x = 6; 
    assert([&]() { return x == 6; }); 
} 
+1

這可行,但寫起來很尷尬。 'assert_with_reason([&](){return glGetError()== GL_NO_ERROR); });' –

2

我很喜歡用宏來達到這個目的。是的,我知道,宏是邪惡,但就像刀(使用錯誤)是邪惡的,他們派上用場,如果你正確使用它們。

#define MY_ASSERT(x) do {\ 
     if (is_debug() && !x) assertFailed(__FILE__, __LINE__, __FUNCTION__, #x);\ 
    } while(0); 

現在,您還可以顯示它失敗(my_drawfunc.cpp: 34 : my_do_draw(): assertion failed: glGetError == GL_NO_ERROR或類似的東西。