vanz
vanz

Reputation: 337

Does istream_iterator reuse object?

I'm writing a C++ library to parse WARC files, it contains the classes to store the WARC record and fields data as well as the operator to read the data from some input stream. It has the operator>> to read from a istream and populate the WARCRecord object. I'm able to read from the istream stream and parse it to a WARCRecord object. However, I would like to use a istream_iterator to read all the WARC records from the input stream.

When I use the istream_iterator to iterate until the end of the stream my operator>> receives the same(copy?) object of the last call. Is this the expected behavior or I'm missing some operator/constructor in my class definition?

This is the repository link with unit test to check this behavior: https://github.com/jvanz/libwarc

A simple example to demonstrate the above text:

#include <iostream>          
#include <istream>           
#include <sstream>           
#include <vector>            
#include <iterator>          


class MyClass                
{                            
        public:              
                std::vector<unsigned int> fields;          
        friend std::istream& operator>> (std::istream& is, MyClass& obj);                                              

}; 



std::istream& operator>> (std::istream& is, MyClass& obj){ 
        std::istream::sentry s(is);                        
        if (s) {             
                for (unsigned i = 0; i < 3; i++) {         
                        unsigned f;                        
                        is >> f;                           
                        obj.fields.push_back(f);           
                }            
        }                    
        return is;           
}                            

int main(void)               
{                            
        std::stringstream ss;                              
        ss << 1 << " " << 2 << " " << 3 << "  " << 4 << " " << 5 << " " << 6;                                          
        std::istream_iterator<MyClass> it(ss);             
        std::cout << it->fields.size() << std::endl;       
        it++;                
        std::cout << it->fields.size() << std::endl;       
        return 0;            
}

The output of this program is:

$ ./a.out 
3
6

Notice the accumulation of the fields member size of the MyClass object

Upvotes: 0

Views: 204

Answers (1)

vanz
vanz

Reputation: 337

I checked the /usr/include/c++/7/bits/stream_operator.h from my machine to take a look in the istream_iterator class. As far as I could see, in fact, the class reuses the same object.

 /// Provides input iterator semantics for streams.                                                                                                                                                                                          
  template<typename _Tp, typename _CharT = char,                                                                                                                                                                                              
           typename _Traits = char_traits<_CharT>, typename _Dist = ptrdiff_t>                                                                                                                                                                
    class istream_iterator                                                                                                                                                                                                                    
    : public iterator<input_iterator_tag, _Tp, _Dist, const _Tp*, const _Tp&>                                                                                                                                                                 
    {                                                                                                                                                                                                                                         
    public:                                                                                                                                                                                                                                   
      typedef _CharT                         char_type;                                                                                                                                                                                       
      typedef _Traits                        traits_type;                                                                                                                                                                                     
      typedef basic_istream<_CharT, _Traits> istream_type;                                                                                                                                                                                    

    private:                                                                                                                                                                                                                                  
      istream_type*     _M_stream;                                                                                                                                                                                                            
      _Tp               _M_value;                                                                                                                                                                                                             
      bool              _M_ok;                                                                                                                                                                                                                

    public:                                                                                                                                                                                                                                   
      ///  Construct end of input stream iterator.                                                                                                                                                                                            
      _GLIBCXX_CONSTEXPR istream_iterator()                                                                                                                                                                                                   
      : _M_stream(0), _M_value(), _M_ok(false) {}                                                                                                                                                                                             

      ///  Construct start of input stream iterator.                                                                                                                                                                                          
      istream_iterator(istream_type& __s)                                                                                                                                                                                                     
      : _M_stream(std::__addressof(__s))                                                                                                                                                                                                      
      { _M_read(); }                                                                                                                                                                                                                          

      istream_iterator(const istream_iterator& __obj)                                                                                                                                                                                         
      : _M_stream(__obj._M_stream), _M_value(__obj._M_value),                                                                                                                                                                                 
        _M_ok(__obj._M_ok)                                                                                                                                                                                                                    
      { }                                                                                                                                                                                                                                     

      const _Tp&                                                                                                                                                                                                                              
      operator*() const                                                                                                                                                                                                                       
      {                                                                                                                                                                                                                                       
        __glibcxx_requires_cond(_M_ok,                                                                                                                                                                                                        
                                _M_message(__gnu_debug::__msg_deref_istream)                                                                                                                                                                  
                                ._M_iterator(*this));                                                                                                                                                                                         
        return _M_value;                                                                                                                                                                                                                      
      }                                                                                                                                                                                                                                       

      const _Tp*                                                                                                                                                                                                                              
      operator->() const { return std::__addressof((operator*())); }                                                                                                                                                                          

      istream_iterator&                                                                                                                                                                                                                       
      operator++()                                                                                                                                                                                                                            
      {                                                                                                                                                                                                                                       
        __glibcxx_requires_cond(_M_ok,                                                                                                                                                                                                        
                                _M_message(__gnu_debug::__msg_inc_istream)                                                                                                                                                                    
                                ._M_iterator(*this));                                                                                                                                                                                         
        _M_read();                                                                                                                                                                                                                            
        return *this;                                                                                                                                                                                                                         
      } 

 istream_iterator                                                                                                                                                                                                                        
      operator++(int)                                                                                                                                                                                                                         
      {                                                                                                                                                                                                                                       
        __glibcxx_requires_cond(_M_ok,                                                                                                                                                                                                        
                                _M_message(__gnu_debug::__msg_inc_istream)                                                                                                                                                                    
                                ._M_iterator(*this));                                                                                                                                                                                         
        istream_iterator __tmp = *this;                                                                                                                                                                                                       
        _M_read();                                                                                                                                                                                                                            
        return __tmp;                                                                                                                                                                                                                         
      }                                                                                                                                                                                                                                       

      bool                                                                                                                                                                                                                                    
      _M_equal(const istream_iterator& __x) const                                                                                                                                                                                             
      { return (_M_ok == __x._M_ok) && (!_M_ok || _M_stream == __x._M_stream); }                                                                                                                                                              

    private:                                                                                                                                                                                                                                  
      void                                                                                                                                                                                                                                    
      _M_read()                                                                                                                                                                                                                               
      {                                                                                                                                                                                                                                       
        _M_ok = (_M_stream && *_M_stream) ? true : false;                                                                                                                                                                                     
        if (_M_ok)                                                                                                                                                                                                                            
          {                                                                                                                                                                                                                                   
            *_M_stream >> _M_value;                                                                                                                                                                                                           
            _M_ok = *_M_stream ? true : false;                                                                                                                                                                                                
          }                                                                                                                                                                                                                                   
      }                                                                                                                                                                                                                                       
    };               

Notice the _M_read() does not create new object before call the operator>>

Upvotes: 0

Related Questions