断言和NDEBUG

Pat*_*ick 7 c++ error-handling

在阅读了一些关于异常滥用的线程之后(基本上说,如果函数前置条件不正确,你不想解开堆栈 - 可能表示你的所有内存都已损坏或同样危险)我正在考虑使用assert()更多经常.以前我只使用assert()作为调试工具,我认为这是很多C++程序员使用它的方式.我担心我的错误处理部分会被未来某个时候引入运行时构建的NDEBUG #define关闭.有没有办法绕过这个并让其他人对此有问题(即我应该担心它)?

谢谢,帕特

编辑:我正在阅读的线程的重点是,如果您的应用程序确实存在错误,那么展开堆栈可能会损坏系统,例如,如果析构函数将某些内容写入文件并且文件句柄已损坏.我不建议使用assert进行正常的错误处理.我目前的用例非常弱,但看看你的想法:


  //check later code won't crash the system
  if( buf.length() % 2 )
    return false;
  // do other stuff that shouldn't affect bufs length
  //copy 2 bytes into buf at a time, if length is odd then don't know 
  //what will happen so use assert to make sure it can't damage anything
  assert( !(buf.length() % 2) );
  for( i = 0; i != buf.length(); i += 2 )
    memcpy( buf + i, data, 2 );
 

edit2:讨论在这里:http: //groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/80083ac31a1188da

Dav*_*ole 8

您可以构建自己的断言而不是使用库存C断言.您的断言不会被禁用.

看一下在/usr/include/assert.h(或者任何地方)中如何实现assert().它只是一些预处理器魔术,最终称为"断言失败"功能.

在我们的嵌入式环境中,我们一直在替换assert().


Car*_*org 7

好吧,一个失败的断言是一个错误,不多也不少。与取消引用空指针相同,只是您自己给了您的软件以打击您的棒。勇敢的决定,你值得称赞!

用异常跳出问题几乎没有帮助,它不会修复错误。所以我建议实现你自己的 ASSERT() 宏,它:

  • 尝试收集尽可能多的有关失败的数据(断言表达式、堆栈跟踪、用户环境等)
  • 努力使用户尽可能容易地向您报告,并且
  • 弹出一个消息框,为给您带来的不便表示歉意,并残酷地中止了该应用程序。

如果性能是一个问题,您可以考虑使用某种从发布版本中消失的 SOFT_ASSERT() 宏。

  • 第 4 步:将数据发布到您的服务器并自动打开一个错误。 (4认同)

Lar*_*itz 7

我喜欢定义自己的断言宏.我总是进行两次ASSERT测试(即使对于优化的构建),DASSERT只对调试版本有影响.您可能希望默认为ASSERT,但如果测试的内容很昂贵,或者性能敏感区域的内部循环内的断言可以更改为DASSERT.

另外,请记住,断言应仅用于完全无意义的条件,这些条件表明程序中存在逻辑错误,并且无法从中恢复.这是对编程正确性的测试.永远不应该使用断言来代替错误处理,异常或健壮性,并且你永远不应断言与格式错误或不正确的用户输入相关的任何内容 - 这样的事情应该优雅地处理.断言只是一个受控制的崩溃,您有机会输出一些额外的调试信息.

这是我的宏:

/// ASSERT(condition) checks if the condition is met, and if not, calls
/// ABORT with an error message indicating the module and line where
/// the error occurred.
#ifndef ASSERT
#define ASSERT(x)                                                      \
    if (!(x)) {                                                         \
        char buf[2048];                                                 \
        snprintf (buf, 2048, "Assertion failed in \"%s\", line %d\n"    \
                 "\tProbable bug in software.\n",                       \
                 __FILE__, __LINE__);                                   \
        ABORT (buf);                                                    \
    }                                                                   \
    else   // This 'else' exists to catch the user's following semicolon
#endif


/// DASSERT(condition) is just like ASSERT, except that it only is 
/// functional in DEBUG mode, but does nothing when in a non-DEBUG
/// (optimized, shipping) build.
#ifdef DEBUG
# define DASSERT(x) ASSERT(x)
#else
# define DASSERT(x) /* DASSERT does nothing when not debugging */
#endif
Run Code Online (Sandbox Code Playgroud)