1. 程式人生 > >C++中istream_iterator和ostream_iterator的用法

C++中istream_iterator和ostream_iterator的用法

寫在前面

今天在看《STL原始碼剖析》的時候,看到了配接器中的ostream iterator,其中包含istream_iterator以及ostream_iterator以及更多,感覺這兩個都十分重要,所以在這裡介紹一下

istream_iterator

原始碼:

template <class T, class Distance = ptrdiff_t> 
class istream_iterator {
  friend bool
  operator== __STL_NULL_TMPL_ARGS (const istream_iterator<T, Distance>& x,
                                   const istream_iterator<T, Distance>& y);
protected:
  istream* stream;
  T value;
  bool end_marker;                                 //判斷是否讀入結束符,比如C語言中的EOF等等
  void read() {                                    //其中呼叫的讀取函式
    end_marker = (*stream) ? true : false;
    if (end_marker) *stream >> value;              //讀入value
    end_marker = (*stream) ? true : false;
  }
public:
  typedef input_iterator_tag iterator_category;   
  typedef T                  value_type;
  typedef Distance           difference_type;
  typedef const T*           pointer;
  typedef const T&           reference;

  istream_iterator() : stream(&cin), end_marker(false) {} //預設建構函式,不會觸發輸入操作
  istream_iterator(istream& s) : stream(&s) { read(); }   //這種建構函式,後面就緊跟著讀取一個數據
  reference operator*() const { return value; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
  istream_iterator<T, Distance>& operator++() {          //重點過載operator++
    read(); 
    return *this;
  }
  istream_iterator<T, Distance> operator++(int)  {      //將operator++過載為輸入操作
    istream_iterator<T, Distance> tmp = *this;
    read();
    return tmp;
  }
};

構造方法:

	istream_iterator<int> intie(cin);                //後面緊跟要輸入一個數據
	istream_iterator<int> intie_();                  //預設構造方法

通過上面的原始碼知道,當呼叫istream_iterator物件的operator++操作時,就會被過載為輸入一個物件

ostream_iterator

原始碼:

template <class T>
class ostream_iterator {
protected:
  ostream* stream;                                                          
  const char* string;                                                       //可以包含第二個引數,輸出對應的資料後,輸出此stream
public:
  typedef output_iterator_tag iterator_category;                            //迭代器型別
  typedef void                value_type;
  typedef void                difference_type;
  typedef void                pointer;
  typedef void                reference;

  ostream_iterator(ostream& s) : stream(&s), string(0) {}                 //預設一個引數的建構函式,預設string為空
  ostream_iterator(ostream& s, const char* c) : stream(&s), string(c)  {} //包含string的建構函式
  ostream_iterator<T>& operator=(const T& value) {                        //重點!!!過載operator=操作,轉換為輸出此value
    *stream << value;
    if (string) *stream << string;
    return *this;
  }
  ostream_iterator<T>& operator*() { return *this; }                       //都返回本身
  ostream_iterator<T>& operator++() { return *this; } 
  ostream_iterator<T>& operator++(int) { return *this; } 
};

構造方式:

	ostream_iterator<int> outie(cout);                           //string預設為null
	ostream_iterator<int> outie_(cout, " !! ");                  //同時也構造string

通過原始碼看出,當ostream_iterator遇到operator=操作是,會被過載為輸出操作

具體用法

使用ostream_iterator以及istream_iterator的時候,要確保使用對應的方法,例:

#include <iostream>
#include <thread>
#include <vector>
#include <numeric>
#include <algorithm>
#include <cstring>
#include <deque>
#include <iterator>
using namespace std;

int main()
{
	deque<int> id;

	istream_iterator<int> intie(cin),eos;                     //開始觸發一次輸入   
	copy(intie, eos, inserter(id, id.begin()));               //迭代器型別為InputIterator,所以這裡呼叫copy的時候採用*result = *first;版本,會使用過載型別 ,那麼就會轉換為插入操作      
															  //其中++first會繼續呼叫下一個,然後過載為新的輸入
	
	ostream_iterator<int> outie(cout, " ");                  //deque的迭代器型別為random_access_iterator,也會是 *result = *first;呼叫賦值操作  result++操作,返回本身,不影響後面的輸出操作
	copy(id.begin(), id.end(), outie);                       //將=操作,轉換為輸出操作
	cout << endl;
	
	system("pause");
}

我們這裡使用的第一個copy方法,裡面採用迴圈賦值的方式進行操作,如下:

template <class InputIterator, class OutputIterator>
inline OutputIterator __copy(InputIterator first, InputIterator last,      //迭代器型別為input_iterator
                             OutputIterator result, input_iterator_tag)
{
  for ( ; first != last; ++result, ++first)                               //直接以迭代器是否相等來進行判斷迴圈是否繼續進行,速度慢
    *result = *first;
  return result;
}

第二個copy方法,也是採用迴圈賦值的方式操作(因為deque中迭代器的型別為:random_access_iterator_tag):

template <class RandomAccessIterator, class OutputIterator, class Distance>
inline OutputIterator
__copy_d(RandomAccessIterator first, RandomAccessIterator last,           //雙向可執行,以n為執行次數,速度快
         OutputIterator result, Distance*)
{
  for (Distance n = last - first; n > 0; --n, ++result, ++first)    
    *result = *first;
  return result;
}

所以可以直接呼叫ostream_iterator的物件,進行文字輸出

同時copy函式中的++first操作,也會呼叫istream_iterator物件的++操作,對文字進行輸入,在第一個copy函式中的inserter引數為iterator adpapters,可以將賦值操作轉換為插入操作,將輸入內容插入到deque中。

參考書籍

《STL原始碼剖析》侯捷著