【问题标题】:Implement Iterators Even When Not Needed? C++即使在不需要时也实现迭代器? C++
【发布时间】:2013-05-18 21:12:17
【问题描述】:

我有一个名为“ntuple”的容器,它本质上是一个 C 数组和长度。它的主要目的是作为多维数学函数的参数。到目前为止,它真的很快,并且利用了表单的多个构造函数

ntuple(double x, double y, double z)
{
    size = 3;
    vec = new double[size];
    vec[0] = x;
    vec[1] = y;
    vec[2] = z;
}

每次我使用更高维度但已知的函数时,我只需添加一个新的构造函数。我也有一个数组:

ntuple(double* invec, long unsigned insizesize)

为了使我的代码与常规 c++ 代码更兼容,我应该实现一个 ntuple 迭代器类吗?我所做的一切都不需要一个,似乎它只会减慢一切。但是我读得越多,为了与标准 C++ 代码兼容而使用迭代器似乎就越重要。

我担心当有人尝试使用我的代码时,它与他们期望使用的标准技术不能很好地结合。但我的 ntuple 类的目的只是将参数带入函数中。

我是否应该以降低代码速度为代价实现迭代器作为预防措施(如果其他人会尝试在其上使用 STL)?

谢谢。

【问题讨论】:

  • 正确实现的迭代器不会影响其他任何东西的速度。
  • 您的ntuple 不是std::vector<double> 有什么原因吗?这个理由有用吗?
  • @user2303321 在 32 位的 MSVC2012 中,sizeof(std::vector) 是 12 字节。您的课程似乎至少有 8 个字节。您正在进行手动内存管理,因为您不希望函数参数大 4 个字节? push_back 和所有其他方法的存在不会增加 std::vector 实例的大小,也不会影响使用它的运行时成本。您可以将参数设为std::vector<double> const&,并且您有一个不可变的doubles 的不可变容器,几乎可以肯定它比ntuple 写得更好......
  • @user2303321 没有。成员函数不占用实例中的空间。而且你不会在你的类中存储一个迭代器,当被问到时你会产生一个迭代器。
  • @user2303321:成员函数当然不会占用对象中的空间。但是很高兴看到您在决定哪种解决方案最好之前甚至没有费心进行测量,根据您的说法,这是对性能非常敏感的代码。很高兴看到这里维护着最引以为豪的计算机科学传统......

标签: c++ stl iterator


【解决方案1】:

为围绕 C 数组的包装器实现迭代器很简单——只需分别返回指向 beginend 的第一个和最后一个元素的指针,并将非虚拟方法添加到POD 课程不会减慢任何速度。通过这些方法访问数组不会比使用数组索引查找慢,并且在某些情况下可能更快。如果你不使用它们,你的代码也不会运行得更慢。

作为一个优势,在 C++11 中,如果您有 beginend 方法,std::beginstd::end 会找到它,而 for( auto x: container ) { /* code */ } 将适用于您的类型。

由于这似乎是一个 X/Y 问题,我怀疑您的问题之一是您根本不应该使用 ntuple 类。 std::vector<double> 已经是一个写得很好的 C 样式数组的薄包装器。要通过它而无需复制它,std::vector<double> const&

顺便说一句,STL 是指派生std 的模板组件的库。它在一些方面与std 库略有不同。

【讨论】:

    【解决方案2】:

    是的,使用向量,但是(如果内存中确实有大量数据)要非常小心地管理向量的内存。那么你真的会有这 4 字节的开销(浪费在容量上)。

    • 始终创建具有明确大小的向量,或创建空并使用 resize()
    • 使用索引填充向量(就像 vec[0] = ...)
    • 永远不要使用 push_back - 它可以请求比需要更多的内存(两倍)

    您也可以像这样使用继承向量来强制执行此规则(尽管有时不推荐这种做法)

    class ntuple: public std::vector<double> {
    private:
        typedef std::vector<double> super;
        void push_back(double); // do not implement
        // also forbid pop_back()
    public:
        ntuble(double a, double b) {
          resize(2);
          (*this)[0] = a;
          (*this)[1] = b;
        }
        ntuple(double* invec, long unsigned size)
          : super(invec, invec + size)
        {
        }
        // all your other convenient constructors here
    };
    

    仍然可以使用 begin() 和 end() 方法访问迭代器

    【讨论】:

      猜你喜欢
      • 2014-08-14
      • 1970-01-01
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多