2013-07-25 27 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或类似的东西。