boost:assert

boost.assert库提供了几个可配置的诊断宏,主要工具是BOOST_ASSERT,其行为和用途与<cassert>中的标准库assert类似,提供运行时断言,但是功能有所增强

为使用boost.assert,需要包含头文件<boost/assert.hpp>

基本用法

assert库定义了两个断言宏:

#define BOOST_ASSERT(expr)   assert(expr)
#define BOOST_ASSERT_MSG(expr, msg) assert((expr) && (msg));
  • 第一种形式的BOOST_ASSERT等同于assert宏,断言表达式为真。
  • 第二种形式则允许断言失败时输出描述性字符串,有助于拍错。
  • BOOST_VERIFY和BOOST_VERIFY_MSG都是BOOST_ASSERT的同义词,没有任何区别,仅为了兼容旧版本而存在

宏的参数expr表达式可以是任意(合法的)C++表示。从简单的关系比较到复杂的函数嵌套调用都可以。如果表达式值为true,那么断言成立,程序会继续往下执行,否则断言会引发一个异常,在终端上输出调试信息并终止程序的执行。比如:

BOOST_ASSERT(10 == 0x10);  //断言成立
BOOST_ASSERT(1 == 9);  // 断言失败,抛出异常

BOOST_ASSERT宏仅会在debug模式下生效,在release模式下不会进行编译,不会影响到运行效率。

看个例子:下面程序定义了一个func,使用BOOST_ASSERT确保不会出现除以0的错误:

double func(int x){
    BOOST_ASSERT_MSG(x != 0, "divided by zero");
    return 1.0/x;
}

在debug模式下运行:

int main()
{
    func(0);
    return 0;
}

在这里插入图片描述

禁用断言


断言宏,< boost/assert.hpp>

BOOST_ASSERT

头文件< boost/assert.hpp>用于定义BOOST_ASSERT,它类似于<cassert>中定义的标准assert宏,宏用于boost库和用户代码中。

  • 默认情况下,BOOST_ASSERT(expr)扩展为 assert(expr).
  • 如果#include <boost/assert.hpp> 时定义了宏BOOST_DISABLE_ASSERTS ,那么无论是否定义宏NDEBUG ,BOOST_ASSERT(expr)都会被扩展为((void)0),这允许用户有选择的禁用BOOST_ASSERT而不影响标准assert的定义
  • 如果#include <boost/assert.hpp> 时定义了宏BOOST_ENABLE_ASSERT_HANDLER ,BOOST_ASSERT(expr)将被扩展为:
(BOOST_LIKELY(!!(expr))? ((void)0): ::boost::assertion_failed(#expr,
    BOOST_CURRENT_FUNCTION, __FILE__, __LINE__))
  • 也就是说,先计算expr,如果为false,则自调用boost::assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__))。无论是否定义了NDEBUG,都是这样
  • boost::assertion_failed在< Boost /assert.hpp>中声明为
namespace boost
{
    void assertion_failed(char const * expr, char const * function,
        char const * file, long line);
}
  • 但它从未被定义。期望用户提供适当的定义。

  • 如果在#include <boost/assert.hpp> 时定义了宏BOOST_ENABLE_ASSERT_DEBUG_HANDLER,那么在定义NDEBUG时,BOOST_ASSERT(expr)扩展为((void)0)。否则,行为就好像定义了BOOST_ENABLE_ASSERT_HANDLER一样。

与< cassert>一样,< boost/assert.hpp>可以在一个翻译单元中包含多次。BOOST_ASSERT将按照上面的指定每次重新定义。

BOOST_ASSERT_MSG

宏BOOST_ASSERT_MSG类似于BOOST_ASSERT,但是它需要一个额外的参数:一个字符字面量,提供一个错误消息。

  • 默认情况下,BOOST_ASSERT_MSG(expr,msg)扩展为assert((expr)&&(msg))。
  • 如果在#include <boost/assert.hpp> 时定义了宏BOOST_DISABLE_ASSERTS ,那么无论是否定义宏NDEBUG , BOOST_ASSERT_MSG(expr,msg)扩展为((void)0)
  • 如果#include <boost/assert.hpp> 时定义了宏BOOST_ENABLE_ASSERT_HANDLER ,BOOST_ASSERT_MSG(expr,msg)将被扩展为:
(BOOST_LIKELY(!!(expr))? ((void)0): ::boost::assertion_failed_msg(#expr,
    msg, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__))
  • 也就是说,先计算expr,如果为false,则自调用(BOOST_LIKELY(!!(expr))? ((void)0): ::boost::assertion_failed_msg(#expr, msg, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__))。无论是否定义了NDEBUG,都是这样
  • boost::assertion_failed_msg在< Boost /assert.hpp>中声明为
namespace boost
{
    void assertion_failed_msg(char const * expr, char const * msg,
        char const * function, char const * file, long line);
}
  • 但它从未被定义。期望用户提供适当的定义。

  • 如果在#include <boost/assert.hpp> 时定义了宏BOOST_ENABLE_ASSERT_DEBUG_HANDLER ,那么在定义NDEBUG时,BOOST_ASSERT_MSG(expr)扩展为((void)0)。否则,行为就好像定义了BOOST_ENABLE_ASSERT_HANDLER 一样。

与< cassert>一样,< boost/assert.hpp>可以在一个翻译单元中包含多次。BOOST_ASSERT_MSG将按照上面的指定每次重新定义。

BOOST_VERIFY

宏BOOST_VERIFY与BOOST_ASSERT具有相同的行为,只是传递给BOOST_VERIFY的表达式总是被求值。当断言的表达式具有理想的副作用时,这很有用;当变量仅在断言中使用时,它还可以帮助抑制关于未使用变量的警告。

  • 如果在#include <boost/assert.hpp> 时定义了宏BOOST_DISABLE_ASSERTS ,BOOST_VERIFY(expr)扩展为((void)0)
  • 如果在#include <boost/assert.hpp> 时定义了宏BOOST_ENABLE_ASSERT_HANDLER ,BOOST_VERIFY(expr)扩展为 BOOST_ASSERT(expr).
  • 否则,当NDEBUG被定义时,BOOST_VERIFY(expr)扩展为((void)(expr));当NDEBUG未被定义时,BOOST_ASSERT(expr)扩展为((void)(expr)。

BOOST_VERIFY_MSG

宏BOOST_VERIFY_MSG类似于BOOST_VERIFY,但是它需要一个额外的参数:一个字符字面量,提供一个错误消息。

  • 如果#include<boost/assert.hpp>时定义了宏BOOST_DISABLE_ASSERTS ,则BOOST_VERIFY_MSG(expr,msg)扩展为((void)(expr))
  • 如果#include<boost/assert.hpp>时定义了宏BOOST_ENABLE_ASSERT_HANDLER ,则BOOST_VERIFY_MSG(expr,msg)扩展为BOOST_ASSERT_MSG(expr,msg)
  • 否则,当NDEBUG被定义时,BOOST_VERIFY_MSG(expr,msg)扩展为((void)(expr));当未定义NDEBUG时,扩展为BOOST_ASSERT_MSG(expr,msg)。

BOOST_ASSERT_IS_VOID

宏BOOST_ASSERT_IS_VOID是在BOOST_ASSERT和BOOST_ASSERT_MSG展开为((void)0)时定义的。它的目的是避免编译和潜在地运行仅用于准备要在断言中使用的数据的代码。

  • 默认情况下,如果定义了NDEBUG,则定义BOOST_ASSERT_IS_VOID。
  • 如果定义了宏BOOST_DISABLE_ASSERTS , BOOST_ASSERT_IS_VOID也总是被定义。
  • 如果定义了宏BOOST_ENABLE_ASSERT_HANDLER,则永远不会定义BOOST_ASSERT_IS_VOID。
  • 如果定义了宏BOOST_ENABLE_ASSERT_DEBUG_HANDLER,那么在定义NDEBUG时也定义了BOOST_ASSERT_IS_VOID。
void MyContainer::erase(iterator i)
{
// Some sanity checks, data must be ordered
#ifndef BOOST_ASSERT_IS_VOID

    if(i != c.begin()) {
        iterator prev = i;
        --prev;
        BOOST_ASSERT(*prev < *i);
    }
    else if(i != c.end()) {
        iterator next = i;
        ++next;
        BOOST_ASSERT(*i < *next);
    }

#endif

    this->erase_impl(i);
}

当前函数宏, < boost/current_function.hpp>

BOOST_CURRENT_FUNCTION

  • 头文件中<boost/current_function.hpp>定义了宏BOOST_CURRENT_FUNCTION,类似于C99预定义的标识符__func__
  • BOOST_CURRENT_FUNCTION展开为一个字符串字面值,包含外围函数的(完全限定的,如果可能的话)名称。如果没有封闭函数,则该行为是未指定的。
  • 有些编译器不提供获取当前封闭函数名称的方法。在这样的编译器上,或者在定义宏BOOST_DISABLE_CURRENT_FUNCTION时,BOOST_CURRENT_FUNCTION展开为"(unknown)"
  • BOOST_DISABLE_CURRENT_FUNCTION解决了一个用例,在这个用例中,程序员希望从最终的可执行文件中消除BOOST_CURRENT_FUNCTION产生的字符串字面量,这是出于安全原因。

源码文件位置支持, < boost/assert/source_location.hpp>

描述

  • 头文件 < boost/assert/source_location.hpp>定义了source_location,一个表示源位置的类,包含文件、行、函数和列信息。它类似于c++ 20中的std::source_location,但只需要c++ 03。

  • 宏BOOST_CURRENT_LOCATION创建一个source_location对象,其中包含关于当前源位置的信息。

类摘要

namespace boost
{

struct source_location
{
  constexpr source_location() noexcept;
  constexpr source_location(char const* file, uint_least32_t line,
    char const* function, uint_least32_t column = 0) noexcept;

  constexpr char const* file_name() const noexcept;
  constexpr char const* function_name() const noexcept;
  constexpr uint_least32_t line() const noexcept;
  constexpr uint_least32_t column() const noexcept;
};

template<class E, class T>
  std::basic_ostream<E, T> &
  operator<<( std::basic_ostream<E, T> & os, source_location const & loc );

} // namespace boost

#define BOOST_CURRENT_LOCATION \
  ::boost::source_location(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION)

source_location

constexpr source_location() noexcept;
  • 效果:构造一个source_location对象,其中file_name()和function_name()返回"(unknown)",line()和column()返回0。
constexpr source_location(char const* file, uint_least32_t line,
  char const* function, uint_least32_t column = 0) noexcept;
  • 效果:构造一个source_location对象,其中file_name()返回file, function_name()返回function, line()返回line参数,column()返回column参数。
template<class E, class T>
  std::basic_ostream<E, T> &
  operator<<( std::basic_ostream<E, T> & os, source_location const & loc );
  • 效果:将loc的字符串表示形式输出到os。
  • 返回值:os

BOOST_CURRENT_LOCATION

  • 当BOOST_DISABLE_CURRENT_LOCATION没有定义时,BOOST_CURRENT_LOCATION的定义是:
#define BOOST_CURRENT_LOCATION \
  ::boost::source_location(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION)
  • 否则,BOOST_CURRENT_LOCATION的定义是:
#define BOOST_CURRENT_LOCATION ::boost::source_location()

这允许出于安全原因生成不包含识别信息的可执行文件。