跳转到内容

更多 C++ 习语/迭代器对

来自 Wikibooks,开放的书籍,开放的世界

迭代器对

[编辑 | 编辑源代码]

指定一个数据值的范围,而无需担心用于数据值的底层数据结构。

也称为

[编辑 | 编辑源代码]

有时这被称为迭代器范围。

众所周知,使用复制构造函数从另一个 vector<int> 创建 vector<int> 是很有用的。类似地,使用应用于成员模板构造函数的 通过成员模板强制转换 习语,从 vector<int> 创建 vector<double> 是很有用的。下面给出了一个代码示例。

template <class T>
class vector
{
  public:
    vector (const vector<T> &); // copy constructor
    template <class U>
    vector (const vector<U> &); // constructor using Coercion by Member Template Idiom.
};

vector 接口对于某些需求来说仍然不够灵活。例如,vector 无法从列表或集合或 POD 数组创建自身。

template <class T>
class vector
{
  public:
    vector (const list<T> &); 
    // constructor must know the interface of list<T> (not necessarily std::list)
    vector (const set<T> &); 
    // constructor must know the interface of set<T> (not necessarily std::set)
    vector (const T * pod_array);
    // another constructor - does not know where pod_array ends - too inflexible!
};

迭代器对是一种解决此挑战的习语。它基于迭代器设计模式(显然!)。迭代器模式的意图:提供一个遍历某些聚合结构的对象,抽象出对该结构实现的假设。

解决方案和示例代码

[编辑 | 编辑源代码]

一对迭代器用于指定一个值的范围的开始和结束。凭借迭代器设计模式,无论是谁(在我们的示例向量中)使用迭代器对习语,都可以访问范围而无需担心聚合数据结构的实现。唯一的要求是迭代器应该公开一个固定的、最小的接口,例如前增量运算符。

template <class T>
class vector
{
    T * mem;
  public:
    template <class InputIterator>
    vector (InputIterator begin, InputIterator end) // Iterator-pair constructor
    {
      // allocate enough memory and store in mem.
      mem=new T[std::distance(begin, end)];
      for (int i = 0; begin != end; ++i)
      {
        mem[i] = *begin;
        ++begin;
      }
    }
};
int main (void)
{
  std::list<int> l(4);
  std::fill(l.begin(),l.end(), 10);    // fill up list using iterator pair technique.
  std::set<int> s(4);
  std::fill(s.begin(),s.end(), 20);    // fill up set using iterator pair technique.

  std::vector<int> v1(l.begin(), l.end());  // create vector using iterator pair technique.
  std::vector<int> v2(s.begin(), s.end());  // create another vector.
}

迭代器对习语通常与成员模板结合使用,因为迭代器的确切类型不是先验知道的。它可以是 set<T>::iterator 或 list<T>::iterator 或 POD 数组。无论类型如何,以迭代器对表示的任何通用算法都可以工作。通常使用说明迭代器类型应该建模的概念很有用。在上面的示例中,迭代器至少需要建模 InputIterator 概念。有关迭代器类别(标签)及其用法的更多信息,请参见标签分派习语。

有时迭代器对习语是不可避免的。例如,要从带有嵌入空字符的字符缓冲区构造一个 std::string,迭代器对习语是不可避免的。

char buf[] = { 'A', 'B', 0, 'C', 0, 'D'};
std::string str1 (buf); // only creates "AB"
std::string str2 (buf, buf + sizeof (buf) / sizeof (*buf)); // Using iterator pair. Creates "AB_C_D"
// buf is start of the range and buf + sizeof (buf) / sizeof (*buf) is the end of the range.

std::cout << str1 << " length = " << str1.length() << std::endl; // AB length = 2
std::cout << str2 << " length = " << str2.length() << std::endl; // AB_C_D length = 6

已知用途

[编辑 | 编辑源代码]

所有标准容器

[编辑 | 编辑源代码]
华夏公益教科书