向量/数组边界仅在声明定义时检查

vector/array bounds check only when a define is declared

本文关键字:声明 定义 检查 数组 边界 向量      更新时间:2023-10-16

我创建了自己的容器,该容器是从向量继承的。我想以一种由 #define 决定检查边界的方式重新实现operator[]

所以举个例子,忽略模板参数表,因为它们既复杂又无关紧要

class MyArray : vector<double>
{
    //...
    virtual double& operator[](const size_type& index);
    virtual const double& operator[](const size_type& index) const;
    //...
}

double& MyArray::operator[](const size_type& index)
{
    #ifdef DEBUG_ENABLED
        return this->at(index);
    #else
        return (*this)[index];
    #endif
}

但是,这不起作用,因为由于operator[]是重载的,因此在 #else 处调用 operator[] 将变得递归。

我想根据我的 #define 进行边界检查,而不是基于我使用的是std::vector<>::at()还是std::vector<>::operator[]

我该如何解决这个问题?

编辑:由于它提供了很多使用std::vector作为成员而不是继承,我必须提到这样做对我来说不是一个好的解决方案,因为我必须重新实现std::vector的所有成员函数。这可不是那么令人愉快的!

只需根据需要调用基类成员函数:

double& operator[](size_type index)
{
    #ifdef DEBUG_ENABLED
        return std::vector<double>::at(index);
    #else
        return std::vector<double>::operator[](index);
    #endif
}

您也应该提供此内容的const版本。另请注意,您可能不希望将此运算符设为virtual

首先,从标准容器派生不是一个好主意,因为它们缺乏正确支持用作基类的功能(例如虚拟析构函数)。 标准容器的目的是它们不会用作基础。

但是,如果必须执行此操作,请添加此内容;

class MyArray : vector<double>
{
    //   all your other stuff
    typedef vector<double> Base;
};
double& MyArray::operator[](const size_type& index)
{
    #ifdef DEBUG_ENABLED
        return this->at(index);
    #else
        return (*((Base *)this))[index];
    #endif
}

函数中的类型转换通常被认为最好使用static_cast来完成,但你明白了。

最好使容器成为类的成员,并将运算符函数的各种成员转发到包含的成员。

class MyArray
{
    //   all your other stuff
   private:
       std::vector<double> data;

};
double& MyArray::operator[](const size_type& index)
{
    #ifdef DEBUG_ENABLED
        return data.at(index);
    #else
        return data[index];
    #endif
}

最后,无论哪种方式,operator[]()都不必是虚拟的。

"由于使用 std::vector

作为成员而不是继承提供了很多东西,我不得不提到这样做对我来说不是一个好的解决方案,因为我必须重新实现 std::vector 的所有成员函数。这可不是那么令人愉快的!

你不必这样做。我在这里使用继承来减轻压力。

#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class Vector_ : private vector<T>
{
public:
    virtual ~Vector_(){}
    virtual const T& operator[](const size_t index);
    virtual const T& at(const size_t index);
};
/*
<<I would like to make the check for bounds based on my #define, and  not based on
std::vector<>::at() or std::vector<>::operator[]. >>
*/
template <typename T>
const T& Vector_<T>::operator[](const size_t index)
{
#ifdef DEBUG_ENABLED
    return (*((vector<T>*)this))->at(index)
#else
    return (*((vector<T> *)this))[index];
#endif
}   
template <typename T>
const T& Vector_<T>::at(const size_t index)
{
#ifdef DEBUG_ENABLED
    return (*((vector<T>*)this))->at(index)
#else
    return (*((vector<T>*)this))[index];
#endif
}
//test...
Vector<int>_ vec;
vec.push_back(3);
vec[2]; or vec.at(2); //no exception
#define DEBUG_ENABLED
vec[2]; or vec.at(2);  //exception