2011-04-19 60 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從文件中讀取這些元素的列表。