Boost C++ 库

...世界上最受尊敬和专家设计的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ 编码标准

Boost.MultiIndex 教程:调试支持



目录

调试支持

契约式设计的概念最初是作为 Bertrand Meyer 的 Eiffel 语言的一部分开发的,它围绕库用户和实现者之间的契约制定展开,其中第一个要求在调用库的方法时传递的值要遵守一些前提条件,而实现者则保证结果满足某些约束(后置条件),以及遵守指定的内部一致性规则,称为不变式。 Eiffel 通过分别使用 requireensureinvariant 结构来原生支持刚才描述的契约的三个部分。

C++ 不直接支持契约式设计技术:这些通常作为断言代码实现,并且出于性能原因经常在发布模式下关闭。 遵循这种方法,Boost.MultiIndex 提供了两种不同的调试模式

这两种模式彼此独立,可以单独打开或关闭。 重要的是要注意,安全模式检测到的错误原则上是由于用户程序中的代码错误造成的,而不变式检查模式检测到的是 Boost.MultiIndex 实现中潜在的内部错误。

安全模式

将前提条件检查工具添加到 STL 作为调试辅助的想法最初是由 Cay S. Horstmann 在他的 安全 STL 库中引入的,后来被 STLport 调试模式 采用。类似地,Boost.MultiIndex 具有所谓的安全模式,在处理库的迭代器和函数时,会检查各种前提条件。

Boost.MultiIndex 安全模式通过全局定义宏 BOOST_MULTI_INDEX_ENABLE_SAFE_MODE 来设置。错误条件通过宏 BOOST_MULTI_INDEX_SAFE_MODE_ASSERT 进行检查,该宏默认解析为对 BOOST_ASSERT 的调用。

如果用户决定定义自己的 BOOST_MULTI_INDEX_SAFE_MODE_ASSERT 版本,它必须采用以下形式

BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code)

其中 expr 是检查的条件,error_codesafe_mode::error_code 枚举的一个值

namespace boost{

namespace multi_index{

namespace safe_mode{

enum error_code
{
  invalid_iterator,             // vg. default cted or pointing to erased element
  not_dereferenceable_iterator, // iterator is not dereferenceable
  not_incrementable_iterator,   // iterator points to end of sequence
  not_decrementable_iterator,   // iterator points to beginning of sequence 
  not_owner,                    // iterator does not belong to the container
  not_same_owner,               // iterators belong to different containers
  invalid_range,                // last not reachable from first
  inside_range,                 // iterator lies within a range (and it mustn't)
  out_of_bounds,                // move attempted beyond container limits
  same_container,               // containers ought to be different
  unequal_allocators            // allocators ought to be equal
};

} // namespace multi_index::safe_mode

} // namespace multi_index

} // namespace boost

例如,以下 BOOST_MULTI_INDEX_SAFE_MODE_ASSERT 的替换会抛出异常而不是断言

#include <boost/multi_index_container/safe_mode_errors.hpp>

struct safe_mode_exception
{
  safe_mode_exception(boost::multi_index::safe_mode::error_code error_code):
    error_code(error_code)
  {}

  boost::multi_index::safe_mode::error_code error_code;
};

#define BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) \
if(!(expr)){throw safe_mode_exception(error_code);}

// This has to go before the inclusion of any header from Boost.MultiIndex,
// except possibly safe_error_codes.hpp.

其他可能性,例如输出到日志或触发某种警报,也是可以实现的。

警告:安全模式会在空间和时间方面给程序增加非常重要的开销,因此通常不应为 NDEBUG 构建设置它。 此外,此模式仅用作调试辅助,程序不得将其作为正常执行流程的一部分依赖于它:特别是,不保证所有可能的前提条件错误都会被诊断出来,或者检查在库的不同版本中保持稳定。

序列化和安全模式

从存档恢复的迭代器不受安全模式检查的约束。 这是因为不可能仅从序列化信息中自动知道迭代器关联的 multi_index_container。 但是,如果需要,可以使用以下解决方法将恢复的迭代器转换为已检查的值

employee_set es;
employee_set::nth_index<1>::iterator it;

// restore es and it from an archive ar
ar>>es;
ar>>it; // it won't benefit from safe mode checks

// Turn it into a checked value by providing Boost.MultiIndex
// with info about the associated container.
// This statement has virtually zero cost if safe mode is turned off.
it=es.project<1>(it);

不变式检查模式

可以通过全局定义宏 BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING 来设置 Boost.MultiIndex 的所谓不变式检查模式。 当此模式生效时,Boost.MultiIndex 的所有公共函数都将执行旨在确保所管理数据结构的基本内部不变式得到维护的执行后测试。

如果不变式测试失败,Boost.MultiIndex 将通过一元宏 BOOST_MULTI_INDEX_INVARIANT_ASSERT 指示失败。 除非用户为此宏提供定义,否则它默认为 BOOST_ASSERT。 此类断言原则上应被视为库中的错误。 请将此类问题以及尽可能多的上下文信息报告给库的维护人员。

建议 Boost.MultiIndex 的用户始终在调试版本中设置不变式检查模式。




修订于 2020 年 5 月 9 日

© 版权所有 2003-2020 Joaquín M López Muñoz。根据 Boost 软件许可证,版本 1.0 分发。(请参阅随附文件 LICENSE_1_0.txt 或复制于 https://boost.ac.cn/LICENSE_1_0.txt