“const_iterator” 真的需要与 “iterator” 不同吗?

4

假设我定义了一种容器A

struct A
{
    iterator begin(){ return iterator(this,0); }
    const iterator cbegin() const { return iterator(this, last());}
    //...
};

假设现在我想声明 iterator(A 的一部分):
struct A::iterator
{
    iterator ( A* ptr, size_t idx){};
    //...
};

我会这样使用:

const A a;
A::iterator it = a.cbegin();

这种方法行不通,因为传递给iterator构造函数的指针是非const的。

理想的解决方案是提供一个返回const对象的特定构造函数:

const A::iterator( const StringUtfInterface *p, size_t s); //Not valid

很明显,在C++中这是不合法的。我想知道解决这个问题的方法是什么?

我真的需要声明/定义一个新的const_iterator类吗?const关键字不够用吗?


相关问题(但不完全相同):


迭代器、常量迭代器和const_iterator之间的区别与普通指针(T *)、常量指针(T * const)和指向常量的指针(T const *)之间的区别相同。你需要这三种类型。 - n. m.
2个回答

4

const关键字不够用吗?

实际上,const关键字有点过头了:它强制你写

const A::iterator it = a.cbegin();

这会阻止您之后使用 ++it

您需要提供两个独立的类,但这并不意味着您必须将代码写两次。您可以以这样的方式构建迭代器的实现,即在常量和非常量迭代器的实现中都嵌入一个通用的类来完成所有工作,并将嵌入式实现的相关方法公开给调用者。


你建议将const_iterator从iterator扩展,将iterator从const_iterator扩展,还是使用模板来处理const/non-const类型? - Adrian Maire
@AdrianMaire 我不会将非const的iterator扩展到const_iterator,因为它们提供相同的成员函数和返回不同类型对象的运算符。使用模板可能会起作用,但我认为将通用实现封装为两个单独的类甚至是私有继承自一个公共基类会更加容易。 - Sergey Kalinichenko

1

那么只需重载iterator的构造函数以支持常量容器,如何?

struct A::iterator {
    iterator(A* ptr, size_t idx) {}
    iterator(const A* ptr, size_t idx) {}
    //...
};

以这种方式,不需要定义两个单独的类,您将始终(隐式地)获得取决于容器常数的正确迭代器。
更新
根据评论,您可以使用模板,例如(不完整实现)。
struct A {
  template<class T>
  struct base_iterator {
  private:
    T* _ptr;

  public:
    base_iterator(T* ptr, size_t idx) : _ptr(ptr) {}

    T operator*() { return *_ptr; }
    //...
  };

  typedef base_iterator<A> iterator;
  typedef base_iterator<const A> const_iterator;

  iterator begin() { return iterator(this, 0); }
  const_iterator cbegin() const { return const_iterator(this, 0); }
  //...
};

2
你打算从 operator* 返回什么类型? - Benjamin Lindley
哦!我明白了……现在很明显,我没有实现太多的迭代器,是吧? ;) - cbuchart
使用模板 base_iterator 可能有效,但请记住您需要使 base_iterator<const T>base_iterator<T> 构造。 - Joseph Artsimovich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接