【问题标题】:How does std::copy work with stream iteratorsstd::copy 如何与流迭代器一起工作
【发布时间】:2013-05-19 14:12:25
【问题描述】:

通常的 STL 构造是:

vector<string> col;
copy(istream_iterator<string>(cin), istream_iterator<string>(),
    back_inserter(col));

我们使用istream_iterator 从标准输入 (cin) 复制到向量。

谁能解释这段代码是如何工作的?

我的问题是我不太了解这部分:

istream_iterator<string>(cin), istream_iterator<string>()

【问题讨论】:

  • 你最好阅读《C++ STL》这本书

标签: c++ stl stream iterator


【解决方案1】:

首先,请注意,在这种情况下,根本不需要使用std::copy。您可以直接从迭代器初始化向量:

vector<string> col((istream_iterator<string>(cin)),
                    istream_iterator<string>());

这可能不会让代码更容易理解。

就代码的工作方式而言,它可能比您想象的要简单一些。一个 istream_iterator 模糊地看起来像这样:

template <class T>
class istream_iterator { 
    std::istream *is;
    T data;
public:
    istream_iterator(std::istream &is) : is(&is) { ++(*this); }
    istream_iterator() : is(nullptr) {}

    T operator++() { (*is) >> data; return *this; }
    T operator++(int) { (*is) >> data; return *this; }

    T const &operator*() { return data; }   

    bool operator !=(istream_iterator &end) { return (*is).good(); }
    bool operator ==(istream_iterator &end) { return !(*is).good(); }
};

显然,我要跳过的内容更多,但这是我们在这里最关心的内容。所以,当你创建迭代器时,它会从流中读取(或尝试)一个项目到我称为data 的变量中。当您取消引用迭代器时,它会返回 data。当您递增迭代器时,它会从文件中读取(或尝试)下一项。尽管写得好像它们将一个迭代器与另一个迭代器进行比较,operator==operator!= 实际上只是检查文件的结尾1

然后 std::copy 使用它,它(再次简化)看起来像这样:

template <class InIt, class OutIt>
void std::copy(InIt b, InIt e, OutIt d) { 
    while (b != e) {
        *d = *b;
        ++b;
        ++d;
    }
}

因此,这会从输入迭代器中读取和项目,将该项目写入输出迭代器,然后重复直到当前位置的迭代器与输入末尾的迭代器比较相等(当您到达文件结尾)。请注意,与其他迭代器不同,您可以与 istream 迭代器一起使用的唯一“结束”位置是文件的结尾。


  1. 请注意,从技术上讲,这不是合规行为。我简化了比较以保持简单。两个默认构造的迭代器应该比较相等,如果你从同一个流中构造两个迭代器,它们应该至少在你从流中读取任何内容之前比较相等。不过,这几乎没有什么实际区别 - 您在实际使用中看到的唯一比较是确定您是否已经到达文件末尾。

【讨论】:

  • 流操作符是否可复制?
  • @quant_dev:你的意思是流迭代器吗?如果是这样,是的,但影响不大。具体来说,您可以复制迭代器并取消引用副本——但只要您增加任何迭代器,取消引用除了您刚刚增加的那个之外的任何副本都会给出 UB。
【解决方案2】:

下面的部分答案引自 C++ 标准库:Nicolai M. Josuttis 的教程和参考,稍作调整。

表达式

  istream_iterator<string>(cin)  

创建一个从标准输入流cin 读取的字符串迭代器。模板参数string 指定流迭代器读取此类型的元素。这些元素使用通常的输入运算符 >> 读取。因此,每次算法想要处理下一个元素时,istream 迭代器都会将该需求转换为调用

cin >> string  

字符串的输入运算符通常读取一个由空格分隔的单词。

表达式

istream_iterator<string>()  

调用 istream 迭代器的默认构造函数,该构造函数创建所谓的流结束迭代器。它表示您无法再从中读取的流。字符串结尾迭代器用作end of the range,因此算法copy 会从cin 读取所有字符串,直到它无法再读取为止。

最后一个:

back_inserter(col))

根据 back_inserter 文档:

一个 std::back_insert_iterator 可用于将元素添加到容器 c 的末尾

它将所有读取的字符串添加到col

您可以找到有关std::istream_iteratorstd::back_inserter 的详细信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多