Search code examples
c++serializationiteratorboost-iterators

Using a C++ iterator to read a list from a file?


I am trying to read/deserialize a list of elements from a file (and then filter out some of them). It is a useful approach to use an iterator for this purpose?

My current try is

#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;
};

This does not properly deallocate memory (e.g., readNew returns a pointer to a new Elem), what is the right way to do this? Also, how would one actually use such an iterator, how can the end be determined? Or is there a better approach than using an iterator?


Solution

  • The easy way to do this is to use the 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
                       );
    

    The standard algorithm copies objects (of type YourObjectClass) from the input file and places them into the vector data if the filter functor returns true.

    The only conditions are:

    • YourObjectClass must have an input stream operator
    • YourFilter must overload the operator() for objects of YourObjectClass or be a function that takes a parameter of type YourObjectClass.

    Simple Working Example:

    • My object is a line.
    • Filter out line(s) that start with the letter '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()
                           );
    }