除了爲每個容器定義的迭代器之外,標準庫在頭文件 iterator 中還定義了額外幾種迭代器。這些迭代器包括以下幾種:
插入迭代器
這些迭代器被綁定到一個容器上,可用來向容器插入元素
#include<bits/stdc++.h>
using namespace std;
int main(){
list<int>lis={1, 2, 3, 4, 5};
list<int> lis1,lis2,lis3;
*back_inserter(lis1)=0;//插入迭代器,向這個list插入一個0
copy(lis.begin(),lis.end(),back_inserter(lis1));//向一個容器添加函數
copy(lis.begin(),lis.end(),front_inserter(lis2));//5 4 3 2 1
// copy(lis.begin(),lis.end(),inserter(lis,lis3.begin());
copy(lis.cbegin(), lis.cend(), inserter(lis3, lis3.begin()));
//inserter(container,pos)
//返回通用插入型迭代器,內部會調用容器container的insert(pos)方法將數據插入到pos位置。
for(auto x:lis3)cout<<x<<" ";
return 0;
}
注意:它們是迭代器適配器。back_inserter、front_inserter 和 inserter 分別會調用 push_back、push_front 和 insert,因此只有在容器支持 push_back 的情況下我們纔可以使用 back_inserter,容器支持 push_front 的情況下我們纔可以使用 front_inserter,容器支持 insert 的情況下纔可以調用 inserter
在插入過程中,back_inserter 總是將新元素插入當前容器尾後迭代器之前,front_inserter 總是將新元素插入當前迭代器首元素之前的位置。而當調用 inserter(c, iter) 時,我們得到一個迭代器,接下來使用它時,會將元素插入到 iter 原來所指向的元素之前的位置。即,如果 it 是由 inserter 生成的迭代器,則:
*it = val;
其效果於下下面代碼一樣:
it = c.insert(it, val);// it 指向新加入的元素
++it;// 遞增 it 使他指向原來的元素
iostream 迭代器:
雖然 iostream 不是迭代器,但標準庫定義了可以用於這些 IO 類型對象的迭代器。istream_iterator 讀取輸入流,ostream_iterator 向一個輸出流寫數據。這些迭代器將它們對於的流當作一個特定類型的元素序列來處理。通過使用流迭代器,我們可以用泛型算法從流對象讀取數據以及向其寫入數據。
istream_iterator 操作:
當創建一個流迭代器時,必須指定迭代器將要讀寫的對象類型。一個 istream_iterator 使用 >> 來讀取流。因此,istream_iterator 要讀取的類型必須定義了輸入運算符。反之亦然(我們可以爲任何定義了輸入運算符的類型創建 istream_iterator 對象)。當創建一個 istream_iterator 時,我們可以將它綁定到一個流。也可以默認初始化迭代器,這樣就創建了一個可以當作尾後值使用的迭代器:
#include<bits/stdc++.h>
using namespace std;
int main(){
istream_iterator<int> in(cin);//從cin流讀取int
istream_iterator<int> eof;//沒有綁定流,就是位置迭代器
ifstream init_in("file");
istream_iterator<string> in1(init_in);//從文件讀取
//用流迭代器直接構造容器。
vector<int> vec(in,eof);//最有用的地方,範圍初始化。
// 還可以使用算法直接操作流迭代器
istream_iterator<int> in(cin),eof;
cout<<accumulate(in,eof,0)<<endl;
return 0;
}
istream_iterator 允許使用懶惰求值:
當我們將一個 istream_iterator 綁定到一個流時,標準庫並不能保證迭代器立即從流讀取數據。具體實現可以推遲從流中讀取數據,直到我們使用迭代器時才真正讀取。標準庫中的實現保證的是,在我們第一次解引用迭代器之前,從流中讀取數據的操作已經完成。對於大多數程序來說,立即讀取還是推遲讀取沒什麼差別。但是,如果我們創建了一個 istream_iterator,沒有使用就銷燬了,或者我們正在從兩個不同的對象同步讀取一個流,那麼何時讀取可能就很重要了~
cin定義了一個string流迭代器,卻又定義了一個int流迭代器
ostream_istrator操作
我們可以對任何具有輸出運算符的類定義 ostream_iterator。當創建一個 ostream_iterator 時,我們可以提供(可選的)第二參數,它是一個字符串,在輸出每個元素後都會打印此字符串。此字符串必須是一個 c 風格字符串。必須將 ostream_iterator 綁定到一個指定的流,不允許空的或表示尾後位置的 ostream_iterator。
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> vec={1,2,3,4,5};
ostream_iterator<int> os(cout," ");
for(auto x:vec)*os++=x;
cout<<endl;//刷新操作,使緩衝區清空。
//值得注意的是,可以忽略引用和遞增運算
for(auto x:vec)os=x;
cout<<endl;
copy(vec.begin(),vec.end(),os);//可以使用算法 模板
cout<<endl;
return 0;
}
使用流迭代器處理類類型:
我們可以爲任何定義了輸入運算符的類型創建 istream_iterator 對象。類似的,只要類型有輸出運算符我們就可以爲其定義 ostream_iterator:
#include<bits/stdc++.h>
using namespace std;
class getl{
// 聲明重載運算符函數爲友元函數
friend istream& operator>>(istream&, getl&);
friend ostream& operator<<(ostream&, const getl&);
private:
int x,y;
public :
getl(int a,int b):x(a),y(b){};//這裏構造函數必須寫全,不寫全會報錯、知識量不夠,還不知道爲啥
getl(int a):getl(a,0){};
getl():getl(0,0){};
~getl(){};
};
istream& operator>>(istream &is, getl &it) {
is >> it.x >> it.y;
return is;
}
ostream& operator<<(ostream &os, const getl &it){
os << it.x << " " << it.y ;
return os;
}
int main(){
istream_iterator<getl> is(cin), eof;
ostream_iterator<getl> os(cout,"\n");
vector<getl> d;
while(is!=eof)d.push_back(*is++);
copy(d.begin(),d.end(),os);
cout<<endl;
return 0;
}
注意:只有重載了 >> / << 的類類型才能創建 istream_iterator 或 ostream_iterator 對象
用流迭代器讀寫文件:
#include<bits/stdc++.h>
using namespace std;
string s="C:\\Users\\xizu_ghq\\Desktop\\pre.txt",s1="C:\\Users\\xizu_ghq\\Desktop\\out.txt";
int main(){
ifstream inin(s);
istream_iterator<string> in(inin),eof;
ofstream inout(s1);
ostream_iterator<string> out(inout,"\n");
vector<string> d(in,eof);
copy(d.begin(),d.end(),out);
cout<<endl;
return 0;
}