通过范围检查和带符号的size_type

时间:2019-02-01 09:34:42

标签: c++

我想使用与std :: vector具有相同功能的类,但是

  • std::vector<T>::size_type替换为某个 signed 整数(例如int64_t或简称为int),而不是通常的size_t。当我使用标准矢量接口时,看到编译器在有符号数和无符号数之间进行比较时会产生警告,这非常令人讨厌。我不能只禁用此类警告,因为它们确实有助于捕获编程错误。
  • assert(0 <= i && i < size());放入operator[](int i)内以检查超出范围的错误。据我了解,与调用.at()相比,这是一个更好的选择,因为我可以在发行版本中禁用断言,因此性能将与向量的标准实现相同。对于我来说,std::vector几乎不可能在每次操作之前都没有手动检查范围的情况下使用,因为operator[]是几乎所有与内存访问相关的奇怪错误的源头。

我想到的可能的选择是

  1. 继承自std :: vector。如以下问题所述,这不是一个好主意:Extending the C++ Standard Library by inheritance?
  2. 使用组合(将std :: vector放入我的类中)并重复std::vector的所有接口。这个选项迫使我考虑当前的C ++标准,因为某些方法,迭代器的接口在C ++ 98、11、14、17中略有不同。我想确定的是,当c ++ 20可用时,我可以简单地使用它,而无需重新实现我矢量的所有接口。

3 个答案:

答案 0 :(得分:2)

关于第1点:我们在这里几乎都不会收到这些警告,因为我们在适当的地方使用了向量的size_type和/或在需要时将其强制转换(为安全起见,使用了诸如boost :: numeric_cast之类的'checked'强制转换)。那不是您的选择吗?否则,编写一个为您执行此操作的函数,即非const版本类似于

template<class T>
T& ati(std::vector<T>& v, std::int64_t i)
{
  return v.at(checked_cast<decltype(v)::size_type>(i));
}

是的,继承仍然是一个问题。即使不是,您也会破坏vector的定义(我猜想是Liskov替换原理),因为size_type定义为

an unsigned integral type that can represent any non-negative value of difference_type

因此取决于组合,或者一堆免费的函数,用于使用带符号的size_type和范围检查进行访问。就我个人而言,我会选择后者:工作量少,易于使用,并且您仍然可以将向量传递给功能强大的向量向量,而不会出现问题。

答案 1 :(得分:2)

这是答案更多潜在的问题从注释如下:

  

例如,我不知道如何在一个远程基于换的方式写:

for (int i = a.size() - 2; i >= 0; i--) { a[i] = 2 * a[i+1]; }

您可以将其更改为一个通用的一个是这样的:

std::vector<int> vec1{ 1,2,3,4,5,6};
std::vector<int> vec2 = vec1;

int main()
{
    // generic code
    for ( auto it = vec1.rbegin()+1; it != vec1.rend(); it++ )
    {
       *it= 2* *(it-1);
    }

    // your code
    for (int i = vec2.size() - 2; i >= 0; i--)
    {
        vec2[i] = 2 * vec2[i+1];
    }

    for ( auto& el: vec1) { std::cout << el << std::endl; }
    for ( auto& el: vec2) { std::cout << el << std::endl; }
}

不使用基于用于当不能够相对于所述位置的访问范围内。

答案 2 :(得分:1)

(这不是真正的答案,而是注释,但是有一些代码,所以...)

对于第二部分(在运行时进行范围检查),第三个选项是使用一些宏技巧:

#ifdef DEBUG
  #define VECTOR_AT(v,i) v.at(i)
#else
  #define VECTOR_AT(v,i) v[i]
#endif

这可以通过以下方式使用:

std::vector<sometype> vect(somesize);
VECTOR_AT(vect,i) = somevalue;

当然,这需要以一种非常不标准的方式来编辑代码,这可能不是一种选择。但这确实可以。