根据编译开关/NDEBUG,在std::vector的at()和操作符[]之间进行交换

Swap between at() and operator[] for std::vector depending on compile switch/NDEBUG

本文关键字:操作符 交换 之间 at 开关 编译 NDEBUG vector std      更新时间:2023-10-16

我知道g++(和MSVC)有允许对操作符[]进行边界检查的开关,不幸的是,据我所知,LLVM的libc++没有完整的实现这种开关或调试代码。

在我目前的项目中,我一直在使用我自己的vector实现(我几年前为可移植性写的),它不会抛出异常,并且对operator[]和at(实际上一个调用另一个并且它们的行为相同,因为没有异常)具有基于断言的边界检查。

我将在完成当前程序后移交这个代码库,它可能会使用很长一段时间。因为我不应该被要求维护它或任何东西,我宁愿在任何地方都完全符合标准,我不认为重新实现容器符合标准的精神,(我也高度怀疑我的容器是否像libc++或libstdc++团队写的那样好)。

是否有一些预处理器魔法或类似的,我可以做使operator[]在调试期间表现得像at()(因此它由于未捕获的异常而中止),并在禁用此调试模式时表现得像operator[] ?(项目完全支持c++ 14)

我们可以从vector的主干libc++源代码中看到,在std::vector<>::operator[]中确实有这样一个检查,它经过_LIBCPP_ASSERT

不幸的是,libc++调试特性还不能使用。

:

  • 关注libc++的更新
  • 训练你的团队期望 operator[]默默接受损坏的输入。根据定义,这就是它的作用。依赖于特定于实现的额外的完整性检查是一个非常糟糕的主意。如果你的团队不确定他们在做什么,他们应该写自己的断言。

是否有一些预处理器魔法或类似的,我可以做使operator[]在调试期间表现得像at()(因此它由于未捕获的异常而中止),并在禁用此调试模式时表现得像operator[] ?(项目完全支持c++ 14)

呃…这个怎么样?

const T& your_vector::operator[](std::size_t index) const
{
#ifndef NDEBUG // !! double negative condition
    if(index >= size_) // assume size_ is std::size_t size_; member of class
        throw std::out_of_bounds{"const T& your_vector::operator[]"};
#endif
    return data_[index]; // assume data_ is a native array containing the elements
}
const T& your_vector::at(std::size_t index) const
{
    if(index >= size_) // assume size_ is std::size_t size_; member of class
        throw std::out_of_bounds{"const T& your_vector::at"};
    return data_[index]; // assume data_ is a native array containing the elements
}

在定义DEBUG时,索引操作符的实现与at相同,在未定义宏时更快。