【问题标题】:C++ class for arrays with arbitrary indices具有任意索引的数组的 C++ 类
【发布时间】:2011-01-19 16:57:46
【问题描述】:

是否有任何流行的 C++ 库有一个(或多个)类允许开发人员在不牺牲速度的情况下使用具有任意索引的数组?

为了给这个问题提供更具体的形式,我希望可以编写类似于以下的代码:

//An array with indices in [-5,6)
ArbitraryIndicesArray<int> a = ArbitraryIndicesArray<int>(-5,6);  
for(int index = -5;index < 6;++index)
{
    a[index] = index;
}

【问题讨论】:

  • 有什么理由不能使用std::vector 和偏移量?
  • @David Rodríguez 通过单向数组,您是指常规 C 数组?
  • @ezpz 你的意思是每次我需要访问元素时都使用 std::vector 并写入 v[indedx + offset] 吗?这不好,因为:a)你我将不得不跟踪这一点,因为忘记偏移会导致错误。 b)我正在做数学计算,索引本身看起来像 v[index + degree - gap]。添加数组的偏移量会使它变得更加混乱,并使调试变得如此困难。
  • 对不起,我的意思是一维的(我想知道我在想什么)。问题是您是否要支持多个维度。
  • @Bartłomiej:我说的是在一个薄包装器中使用std::vector。构造函数将获取范围并透明地管理偏移量。界面与您的v[index + degree - gap] 相同

标签: c++ arrays indices


【解决方案1】:

真的,您应该使用带偏移量的向量。甚至是带有偏移量的数组。额外的加法或减法不会对程序的执行速度产生任何影响。

如果您想要与默认 C 数组具有完全相同的速度,您可以将偏移量应用于数组指针:

int* a = new int[10];
a = a + 5;
a[-1] = 1;

但是,不建议这样做。如果你真的想这样做,你应该创建一个包含内联函数的包装类来隐藏可怕的代码。您保持 C 代码的速度,但最终能够添加更多错误检查。

如 cmets 中所述,更改数组指针后,您无法使用该指针进行删除。您必须将其重置为阵列的实际开始。另一种方法是您始终保持指针指向开始,但使用另一个修改后的指针。

//resetting the array by adding the offset (of -5)
delete [] (a - 5);

【讨论】:

  • 您还造成了内存泄漏。
  • 使用-1会不会有问题?因为数组下标实际上是无符号的?
  • @David 不是真的,当您想删除指针时,您只需反转执行的操作以获取偏移数组。
  • @EvilTeach Microsoft 表示支持它们。 msdn.microsoft.com/en-us/library/59682zc4(VS.80).aspx
  • @yacoby 是的。谢谢不错的链接。这是问题的唯一正确答案。
【解决方案2】:

std::vector&lt;int&gt; 可以在这里解决问题。
随机访问向量中的单个元素只需 O(1)。

如果您真的需要自定义索引,您可以根据向量创建自己的小类来应用偏移量。

【讨论】:

    【解决方案3】:

    使用 STL 中的地图类:

    std::map<int, int> a;
    for( int index = -5; index < 6; ++index )
    { 
        a[index] = index; 
    }
    

    map 在内部实现为排序容器,它使用二进制搜索来定位项目。

    【讨论】:

    • O(log n) 的查找时间比数组的 O(1) 慢
    • 替代方案是 std::tr1::unsorted_map ,它是散列映射的当前标准实现,所以大多数时候 O(1)
    • 这行不通。我一直需要 O(1)。
    【解决方案4】:

    [这是一个旧线程,但仅供参考...]

    Boost.MultiArray 具有用于设置任何索引范围的范围系统。

    ObjexxFCL 库中的数组完全支持任意索引范围。

    这些都是多维数组库。对于 OP 1D 数组,上面的 std::vector 包装器就足够了。

    【讨论】:

      【解决方案5】:

      因为我不是很聪明,所以编辑了答案。

      std::vector 和偏移量包装到一个类中并提供operator[]

      template <class T>
      class ArbVector
      {
          private:
              int _offset;
              std::vector<T> container;
          public:
              ArbVector(int offset) : _offset(offset) {}
              T& operator[](int n) { return container[n + _offset] }
      };
      

      不确定这是否编译,但你明白了。

      但不要从 std::vector 派生,请参阅 cmets。

      【讨论】:

      • 永远不要从 STL 容器类派生,因为它们都缺少虚拟析构函数。
      • 不,不,不,永远不要子类化 STL 对象。他们的方法都不是虚拟的,您将在路上遇到问题。将 std::vector 封装在您自己的类中,作为大多数函数的底层向量的通路。
      • std::vector 的 d-tor 没有定义为虚拟的,因此继承它不是一个好主意。
      • 我承认,我不知道这一点......但是在这种特定情况下会出现什么问题?
      • 私有继承也可以
      猜你喜欢
      • 1970-01-01
      • 2010-09-28
      • 2010-10-08
      • 2011-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-24
      相关资源
      最近更新 更多