在C++中实现断言检查的最佳方法是什么?

Mar*_*ram 19 c++ debugging assert debugbreak

我的意思是,我需要做什么才能在我的代码中使用有用的断言?

MFC很简单,我只使用ASSERT(某物).

什么是非MFC方式?

编辑:是否有可能在assert.c中停止断言而不是我的调用assert()的文件?

编辑:<assert.h>&之间有什么区别<cassert>

一般承认的答案:在这篇文章中有很多很棒的答案,我希望我能接受不止一个答案(或者有人将它们全部合并).所以答案会被授予Ferruccio(第一个答案).

Fer*_*cio 29

#include <cassert>

assert(something);
Run Code Online (Sandbox Code Playgroud)

对于编译时检查,Boost的静态断言非常有用:

#include <boost/static_assert.hpp>

BOOST_STATIC_ASSERT(sizeof(int) == 4);  // compile fails if ints aren't 32-bit
Run Code Online (Sandbox Code Playgroud)


Miq*_*lla 13

这取决于您是否正在寻找在Visual C++之外工作的东西.它还取决于您正在寻找的断言类型.

有几种类型的断言:

  1. 预处理程序
    这些断言是使用预处理程序指令完成的.预处理程序#error
    断言仅在预处理阶段进行评估,因此对模板等内容无用.

  2. 执行时间
    这些断言是使用 执行时assert()定义的函数完成的.<cassert>
    时间断言仅在运行时进行评估.正如BoltBait指出的那样,如果NDEBUG定义了宏,则不编译.

  3. 静态
    正如您所说,这些断言是通过使用ASSERT()宏来完成的,但前提是您使用的是MFC.我不知道另一种做静态断言的方法是C/C++标准的一部分,但Boost库提供了另一种解决方案:static_assert.Boost库中
    static_assert函数将在C++ 0x标准中添加.

作为附加警告,assert()Ferruccio建议的功能与MFC ASSERT()宏的行为不同.前者是执行时断言,而后者是静态断言.

我希望这有帮助!


pae*_*bal 10

断言(通常)仅调试

"断言"的问题在于它通常在调试二进制文件中,并且一些开发人员使用它们就像代码仍然在生产中一样.

这本身并不是邪恶的,因为代码应该进行密集测试,因此,产生断言的错误肯定会被发现并被删除.

但有时(大多数时候?),测试并不像想要的那样密集.我不会谈论一份旧工作,直到最后一分钟我们必须编码(不要问......有时候,管理人员只是......咳咳......)......断言你有什么意义添加到下一分钟将编译并作为发布二进制文件传递给客户端的代码?

断言(某些)现实生活中的应用程序

在我们的团队中,我们需要一些东西来检测错误,同时还需要其他东西来处理错误.我们可能在Release Build上需要它.

Assert将仅在调试版本中检测和处理错误.

所以我们添加了一个XXX_ASSERT宏,以及一个XXX_RAISE_ERROR宏.

XXX_ASSERT宏将与ASSERT宏做同样的事情,但它将在Debug和Release中构建.它的行为(写日志,打开消息框,什么都不做等)可以通过.INI文件控制,然后它会中止/退出应用程序.

这被用作:

bool doSomething(MyObject * p)
{
   // If p is NULL, then the app will abort/exit
   XXX_ASSERT((p != NULL), "Hey ! p is NULL !") ;

   // etc.
}
Run Code Online (Sandbox Code Playgroud)

XXX_RAISE_ERROR宏只会"记录"错误,但不会尝试处理它.这意味着它可以将消息记录在文件中和/或打开带有消息的MessageBox和一个继续按钮,另一个用于启动调试会话(根据.INI文件配置).这被用作:

bool doSomething(MyObject * p)
{
   if(p == NULL)
   {
      // First, XXX_RAISE_ERROR will alert the user as configured in the INI file
      // perhaps even offering to open a debug session
      XXX_RAISE_ERROR("Hey ! p is NULL !") ;
      // here, you can handle the error as you wish
      // Than means allocating p, or throwing an exception, or
      // returning false, etc.
      // Whereas the XXX_ASSERT could simply crash.
   }

   // etc.
}
Run Code Online (Sandbox Code Playgroud)

在我们的库中引入一年后,只使用了XXX_RAISE_ERROR.当然,它不能用于应用程序的时间关键部分(我们有一个XXX_RAISE_ERROR_DBG),但在其他地方,它是好的.事实上,人们可以使用任何首选的错误处理,并且可以在开发人员计算机,测试人员甚至用户上随意激活,这非常有用.


phi*_*ant 9

要在第二个"编辑"中回答这个问题:

<assert.h>是C头

<cassert>是C++标准库头文件...它通常包含<assert.h>

  • 而且由于assert()是一个宏而不是一个函数,因此C++头文件不会将它放入std :: namespace中,只是在头文件名中才有区别. (2认同)

Ate*_*ral 6

要在调用assert的文件内部进行分解,可以使用抛出异常或调用的自定义宏__debugbreak:

#define MYASSERT(EXPR, MSG) if (!(EXPR)) throw MSG;
Run Code Online (Sandbox Code Playgroud)

要么:

#define MYASSERT(EXPR) if (!(EXPR)) __debugbreak();
Run Code Online (Sandbox Code Playgroud)


Mic*_*bbé 6

基本断言用法

#include <cassert>

/* Some code later */
assert( true );
Run Code Online (Sandbox Code Playgroud)

最佳实践笔记

断言用于标识应该为true的运行时状态.结果,它们在发布模式下编译.

如果您希望断言始终命中,则可以将false传递给它.例如:

switch ( someVal ):
{
case 0:
case 1:
  break;
default:
  assert( false ); /* should never happen */
}
Run Code Online (Sandbox Code Playgroud)

也可以通过断言传递消息:

assert( !"This assert will always hit." );
Run Code Online (Sandbox Code Playgroud)

成熟的代码库经常扩展断言功能.一些常见的扩展包括:

  • 在每个模块的基础上切换断言以本地化测试.
  • 创建在大多数调试版本中编译的附加断言宏.对于频繁调用的代码(每秒数百万次)并且不太可能不正确,这是理想的.
  • 允许用户禁用当前命中的断言,编译单元中的所有断言或代码库中的所有断言.这会阻止良性断言被触发,从而产生无法使用的构建.


Con*_*tin 5

特定于Microsoft的CRT断言

#include <crtdbg.h>
#include <sstream>
...
// displays nondescript message box when x <= 42
_ASSERT(x > 42);
// displays message box with "x > 42" message when x <= 42
_ASSERTE(x > 42);
// displays message box with computed message "x is ...!" when x <= 42
_ASSERT_EXPR(
   x > 42, (std::stringstream() << L"x is " << x << L"!").str().c_str());
Run Code Online (Sandbox Code Playgroud)