boost:assert 太过爱你忘了你带给我的痛 2022-10-20 13:53 156阅读 0赞 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; } ![在这里插入图片描述][38e45984044c4763a1282a028619eeac.png] # 禁用断言 # -------------------- # 断言宏,< 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() 这允许出于安全原因生成不包含识别信息的可执行文件。 [38e45984044c4763a1282a028619eeac.png]: /images/20221020/d724b1a4b0934ac289fc4878f329f81a.png
还没有评论,来说两句吧...