编译时触发std::vector的范围检查

Compile time triggered range check for std::vector

本文关键字:vector 范围 检查 std 编译      更新时间:2023-10-16

目标:

我希望std::vectoroperator []的范围检查版本用于我的调试构建,而在发布模式下没有范围检查。

调试模式下的范围检查显然对调试有好处,但它会导致我的发布代码减慢5% - 10%,这是我想避免的。

可能的解决方式:

我在Stroustrup的"c++编程语言"中找到了一个解决方案。他做了以下事情:

template <class T>
class checked_vector : public std::vector<T> {
    public:
        using std::vector<T>::vector;
        //override operator [] with at()
};

这是有问题的,因为它继承了具有非虚析构函数的类,这是危险的。(而休息室不太喜欢这个解决方案。)

另一个想法是像这样创建一个类:

template <class T>
class checked_vector {
    std::vector<T> data_;
    public:
        //put all public methods of std::vector here by hand
};

这样做既繁琐又会产生大量的复制粘贴,这也是不好的。

以上两种解决方案的好处是,我可以简单地通过makefile中的宏定义来切换它们的打开和关闭。

问题:

  1. 有更好的解决方案吗?(如果没有,为什么没有?)
  2. 如果没有,是否认为上述其中一种是可以接受的?(我知道这是基于意见的,如果可能的话,请关注第一点。)

如果我没弄错的话,这是Visual Studio的常见情况。使用g++时,必须使用-D_GLIBCXX_CONCEPT_CHECKS -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC调用编译器。(很可能您不需要全部使用这三种,但我使用全部三个系统)。对于其他编译器,请查看文档。标准中未定义行为的目的正是为了允许这种事情发生。

按偏好降序排列:

  • 如果您使用迭代器、范围和迭代而不是索引到容器中,问题就会消失,因为您不再传入需要检查的任意索引。此时,您可以决定用at替换任何需要索引的剩余代码,而不是使用特殊的容器。

  • 用算法扩展,而不是像其中一个注释中建议的那样继承。这几乎肯定是完全内联的,并且符合使用算法而不是附加成员函数的标准。它还具有与任何具有operator[]at的容器一起工作的优点(因此它也可以在deque上工作):

    template <typename Container>
    const typename Container::value_type& element_at(const Container& c, int index)
    {
        // Do checked code here.
    }
    
  • 私下继承std::vectorusing的方法,你需要到你的子类。那么至少你不能不恰当地多态破坏你的子向量