【问题标题】:Trying to implement an iterator without an explicit container尝试在没有显式容器的情况下实现迭代器
【发布时间】:2011-06-16 01:16:39
【问题描述】:

在我最近的question 之后,我正在尝试实现我自己设计的示例。
我有一个基本的结构,但即使在阅读了this,这可能是我见过的最好的教程之后,我仍然很困惑。我想我可能应该将 Chapter._text 转换为流,并为增量运算符做类似的事情

string p = "";
string line;
while ( getline(stream, line) ) {
    p += line;
}
return *p;

但我不确定要使用哪个“样板”类型定义以及如何将所有这些东西放在一起。非常感谢您的帮助

#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class Paragraph {
public:
  string _text;

  Paragraph (string text) {
    _text = text;
  }
};

class Chapter {
public:
  string _text;

  /*  // I guess here I should do something like:
  class Iterator : public iterator<input_iterator_tag, Paragraph> {

  }
  // OR should I be somehow delegating from istream_iterator ? */

  Chapter (string txt_file) {
    string line;

    ifstream infile(txt_file.c_str());
    if (!infile.is_open()) {
      cout << "Error opening file " << txt_file << endl;
      exit(0);
    }
    while ( getline(infile, line) ) {
      _text += (line + "\n");
    }
  }

};

int main(int argc, char** argv) {
  Chapter c(argv[1]);

  // want to do something like:
  // for (<Paragraph>::iterator pIt = c.begin(); pIt != c.end(); pIt++) {
  //    Paragraph p(*pIt);
  //    // Do something interesting with p
  // }

  return 0;
}

【问题讨论】:

  • Chapter::Iterator 应该如何移动? Chapter 类中的唯一数据是成员 _text,它存储输入文件 sans 行结尾的 整个 内容。有什么想法?
  • 谢谢,刚刚更正了行尾。
  • 那么...为什么不直接将整个文件读入内存呢?
  • 总的想法是能够迭代从Chapter on the fly STL风格中提取的段落,而无需将它们显式存储在容器中。这个例子有点做作,但如果文本文件非常大并且我不想将整个内容再次存储为矢量,例如,它可能会很有用
  • 那么……去实现迭代器接口吧!你需要了解什么?我想当你按下“增量”时会发生魔法......你会保留一个指向当前位置的指针吗?

标签: c++ stl iterator


【解决方案1】:

由于您不打算一次加载一章(仅是一个段落),并且您的段落是空的,我认为这可能最好使用单个段落迭代器类来完成

class paragraph_iterator : 
public std::iterator<std::input_iterator_tag, std::string>
{
    std::shared_ptr<std::ifstream> _infile; //current file
    std::string _text; //current paragraph
    paragraph_iterator(const paragraph_iterator &b); //not defined, so no copy
    paragraph_iterator &operator=(const paragraph_iterator &b); //not defined, so no copy
    // don't allow copies, because streams aren't copiable. 
    // make sure to always pass by reference
    // unfortunately, this means no stl algorithms either

public:
    paragraph_iterator(string txt_file) :_infile(txt_file.c_str()) {
        if (!infile.is_open())
            throw std::exception("Error opening file ");
        std::getline(_infile, _text);
    }
    paragraph_iterator() {}
    paragraph_iterator &operator++() {
        std::getline(_infile, _text);
        return *this;
    }
    // normally you'd want operator++(int) as well, but that requires making a copy
    // and std::ifstream isn't copiable.
    bool operator==(const paragraph_iterator &b) const {
        if (_infile.bad() == b._infile.bad())
            return true; //all end() and uninitialized iterators equal
        // so we can use paragraph_iterator() as end()
        return false; //since they all are seperate strings, never equal
    }
    bool operator!=(const paragraph_iterator &b) const {return !operator==(b);}
    const std::string &operator*() const { return _text;}
};

int main() {
    paragraph_iterator iter("myfile.txt");
    while(iter != paragraph_iterator()) {
         // dostuff with *iter
    }

}

流被封装在迭代器中,所以如果我们有两个指向同一个文件的迭代器,它们都会得到每一行。如果您有一个带有两个迭代器的单独章节类,您可能会遇到“线程”问题。这是非常简单的代码,完全未经测试。我确信有一种方法可以使用可复制的迭代器来做到这一点,但要复杂得多。

一般来说,迭代器类的实现与其迭代的数据结构密切相关。否则,我们只有几个通用迭代器类。

【讨论】:

  • 感谢@MooingDuck,我已经使用friend istream&amp; operator&gt;&gt;(istream&amp; i, Paragraph&amp; p) 的方法解决了这个问题,但您的解决方案正是我所追求的。在我对您的代码的初始测试中,我发现的最大问题是未初始化的paragraph_iterator 具有与实际_infile 流相同的位状态,因此主while 循环不会去任何地方。我将它调整为paragraph_iterator() { _infile.setstate(ios::eofbit); },现在它似乎可以工作了。
  • @confusedCoder:再看这段代码,你是对的,它有几个错误。默认构造函数是错误的,等价运算符取消引用空指针,构造函数中有不必要的字符串副本......但概念就在那里。
猜你喜欢
  • 2018-10-22
  • 1970-01-01
  • 1970-01-01
  • 2018-03-31
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多