2011-04-19 97 views
0

我想读/反序列化一个文件中的元素列表(然后过滤掉其中的一些)。为此目的使用迭代器是一种有用的方法?使用C++迭代器从文件中读取列表?

我现在的尝试是

#include <boost/iterator/iterator_adaptor.hpp> 
class ReadIterator : public boost::iterator_adaptor<ReadIterator, Elem *, boost::single_pass_traversal_tag> 
{ 
public: 
    explicit ReadIterator(const char *filename) : reader(filename) {} 

private: 
    friend class boost::iterator_core_access; 

    void increment() { 
     this->base_reference() = reader.readNext(); 
    } 

    Reader reader; 
}; 

这并不正确释放内存(例如,readNew返回一个指向新ELEM),什么是做到这一点的正确方法?另外,如何实际使用这样一个迭代器,如何确定结束?还是有更好的方法比使用迭代器?

+1

你能给我们采样的输入? – wilhelmtell 2011-04-19 04:32:43

回答

4

最简单的方式做,这是使用std :: istream_iterator

std::vector<YourObjectClass> data; 

std::remove_copy_if(std::istream_iterator<YourObjectClass>(file), 
        std::istream_iterator<YourObjectClass>(), 
        std::back_inserter(data), 
        YourFilter 
        ); 

从输入file(类型YourObjectClass)的标准算法拷贝的对象,并将其放置到载体data如果过滤器函子返回true。

唯一条件是:

  • YourObjectClass必须有一个输入流操作者
  • YourFilter必须重载操作符(),用于YourObjectClass的物体或是一个函数,它类型YourObjectClass的参数。

简单的工作实施例:

  • 我的目的是一条线。
  • 筛选出来线(S)以字母 'A'

Exmpale开始:

#include <vector> 
#include <string> 
#include <fstream> 
#include <iterator> 
#include <algorithm> 

struct Line 
{ 
    std::string data; 
}; 
std::istream& operator>>(std::istream& stream, Line& line) 
{ 
    return std::getline(stream, line.data); 
} 
struct AFilter 
{ 
    bool operator()(Line const& line) const 
    { 
     return line.data.size() > 0 && line.data[0] == 'A'; 
    } 
}; 

int main() 
{ 
    std::ifstream  file("Plop"); 
    std::vector<Line> data; 

    std::remove_copy_if(std::istream_iterator<Line>(file), 
         std::istream_iterator<Line>(), 
         std::back_inserter(data), 
         AFilter() 
         ); 
} 
+0

太好了,谢谢你这个精心设计的例子!当'Line'没有默认的构造函数时,如果只有'Line :: Line(std :: istream&in)',有没有办法做到这一点? – hrr 2011-04-19 14:07:36

1

而不是readNext()返回一个原始指针到一个元素,你可以构造调用,以便它返回一个引用计数的智能指针,当指针的引用计数到零时,它会自动释放它的资源?要么是这样,要么你必须找到一种方法来取回指针,以便在通过readNext()的下一次调用分配更多内存之前调用delete时,再次调用increment()

至于“结束”,在这种情况下你可以做的是在你的Reader类中进行一些测试,检测你是否已经达到文件末尾或其他结束场景。如果有,则返回false,否则返回true。例如:

bool increment() 
{ 
    if (reader.not_end_of_file()) 
    { 
     this->base_reference() = reader.readNext(); 
     return true; 
    } 

    return false; 
} 

所以,现在你可以调用increment()在某些类型的循环,你就会知道,当你已经打了最终的文件或一些其他的结局,因为该函数将返回false。

1

为此目的使用迭代器很好。尽管如此,您还没有给出任何迹象表明现有的istream_iterator不适合您的用途。至少在大多数情况下,您只需为单个元素编写operator>>,然后使用std::istream_iterator从文件中读取这些元素的列表。