原书:Essential C++, Stanley B. Lippman, 电子工业出版社, 2013.
章节:第3章 泛型编程风格
环境:CLion + MinGW
-
Standard Template Library(STL)主要由两种组件构成:
(1) 容器,包括vector, list, set, map等类
(2) 泛型算法, 包括find(), sort(), replace(), merge()等 -
顺序性容器:vector和list
关联容器:set和map,map是键值对组合,key用户查找,value表示存储或取出的数据,set仅含有key,可对其进行查询操作
-
泛型算法,泛型指它们和想要操作的元素类型(int, double, string等)无关,和容器(vector, list, array等)也彼此独立
-
泛型算法通过function template技术使其与操作对象的类型相互独立
3.1 指针的算术运算
-
find()函数, 传入任意类型的vector对象和该类型的一个值,若值在vector中,则返回指向该值的指针,否则返回nullptr
// 原书中返回类型为type*, 而vec为const vector<type>的引用, 返回type*使程序可通过该指针改变vector的值, 这是不合理的, 故编译器报错, 应该返回const type* // 倘若想传入vector<type>的引用, 并返回type*, 使得外部程序可借助该指针修改vector的值, 但问题在于该函数无法处理const vector<type>类型 template<typename type> const type* find(const vector<type> &vec, const type &value) { if(!vec) return nulltpr; for(int i = 0; i < vec.size(); ++i) if(vec[i] == value) return &vec[i]; return nullptr; }
(1) 原书中find()函数的返回类型为type*, 而vec为const vector<type>的引用, 返回type*使程序可通过该指针改变vector的值, 这是不合理的, 故编译器报错, 应该返回const type*
(2) 在官网下载的source code, find()函数的返回类型已修改为const type*
-
find()函数查找array中是否存在指定值,且传入参数无需声明array
(1) 方法1,使用参数size指明array的长度
template<typename type> const type* find(const type *p, int size, const type &value) { if(!p || size < 1) return nulltpr; for(int i = 0; i < size; ++i) if(p[i] == value) return &p[i]; return nullptr; }
除了使用p[i]访问数组元素, 也可直接采用*进行提领,两者等效
template<typename type> const type* find(const type *p, int size, const type &value) { if(!p || size < 1) return nulltpr; for(int i = 0; i < size; ++p, ++i) // 在条件中同时进行i和p的递增 if(*p == value) return p; return nullptr; }
(2) 方法2,使用指向末尾的指针代替size
template<typename type> const type* find(const type *p_start, const type *p_end, const type &value) { if(!p_start || !p_end) return nullptr; for(; p_start != p_end; ++p_start) if(*p_start == value) return p_start; return nullptr; }
该函数的调用
int arr[] = {1, 2, 3}; int val = 1; if(find(arr, arr + 3, val)) // 传入数组最后一个元素的下一个地址 cout << "Found." << endl; else cout << "Not found." << endl;
(3) 应用于vector对象
int arr[] = {1, 2, 3}; vector<int> vec(arr, arr + 3); int val = 1; // 传入vec[vec.size()]的地址, 即vec最后一个元素的下一个地址 if(find(&vec[0], &vec[vec.size()], val)) cout << *find(&vec[0], &vec[vec.size()], val) << endl; else cout << "Not found" << endl;
-
指针的算术运算
Q:
++p
为指针的算术运算,假如p的初始地址为1000,执行后结果为?A: 指针的算术运算会把指针所指的类型的大小考虑进去,假如p指向int类型,在int为4 bytes的机器上执行,则p的结果为1004
-
begin和end函数
(1) begin函数返回vector对象的首地址或0
template <typename type> const type* begin(const std::vector<type> &vec){ return vec.empty()? 0: &vec[0]; }
(2) end函数返回vector对象的首地址或0
template <typename type> const type* end(const std::vector<type> &vec){ return vec.empty()? 0: &vec[vec.size()]; }
(3) vector通过begin和end调用find函数
int arr[] = {1, 2, 3}; vector<int> vec(arr, arr + 3); int val = 1; if(find(begin(vec), end(vec), val)) cout << *find(begin(vec), end(vec), val) << endl; else cout << "Not found" << endl;
以上程序可在C++98编译运行,在C++11或更高版本中会发生编译错误,而Essential Cpp也是基于C++98编写的,故可能出现不兼容的情况
error: no matching function for call to 'find(std::vector<int>::iterator, std::vector<int>::iterator, int&)'
3.2 了解Iterator(泛型指针)
-
find()函数若想处理list等容器,无需重写,只要在底层指针的行为之上提供一层抽象,取代程序原本的“指针直接操作”的方式,并把底层指针的处理都放在抽象层中,程序员直接对抽象层操纵,即可在只提供一份find()函数的情况下,处理STL中的所有容器类
-
设计iterator class使得可以使用"和指针相同的语法"对其进行程序的编写,如
// first和last皆为iterator class object, 可以对其进行*/!=/++等运算, 这些运算均由iterator class内相关的inline函数提供 while(first != last){ cout << *first << ' '; ++first; }
-
标准容器中的iterator类
(1) 标准容器中名为begin()的操作函数返回一个指向第一个元素的iterator,名为end()的操作函数返回一个指向最后一个元素的iterator
for(iter = vec.begin(); iter!= vec.end(); ++vec) cout << *iter << ' ';
(2) 定义iterator时,需要提供给iterator的信息包括
1) 迭代对象(某个容器)的类型,决定如何访问下一个元素
2) iterator指向的元素的类型,决定iterator提领操作的返回值
// 可能的定义形式, 但STL并非这样做 iterator<vector, string> iter;
(3) STL定义iterator的方式
vector<string> vec; vector<string>::iterator iter = vec.begin();
双冒号
::
表示iterator是位于string vector定义内的嵌套nested类型 -
const_iterator类
对于const容器应使用const_iterator进行遍历操作,其允许我们读取容器内的元素,但无法进行写入操作
const vector<string> vec; const vector<string>::const_iterator iter = vec.begin();
-
使用iterator
(1) 获取元素值, 提领操作
*iter
cout << *iter << endl;
(2) 调用底部元素(如string)所提供的操作
cout << iter->size() << endl; // 调用iter所指string的方法size(), 打印该string的长度
-
重写find()函数使其支持一对指针,或一对指向某种容器的iterator
template<typename iteratorType, typename elemType> iteratorType find(iteratorType first, iteratorType last, const elemType &value) { for(; first != last; ++first) if(value == *first) return first; return last; }
测试程序
const int arr_size = 3; int arr[arr_size] = {1,2,3}; vector<int> vec(arr, arr + arr_size); list<int> li(arr, arr + arr_size); const int *pa = find(arr, arr + arr_size, 2); if(pa) cout << *pa << endl; vector<int>::iterator iter; iter = find(vec.begin(), vec.end(), 2); if(iter != vec.end()) cout << *iter << endl; list<int>::iterator it; it = find(li.begin(), li.end(), 2); if(it != li.end()) cout << *it << endl;
-
若想在find()函数中赋予equality运算符不同的意义,可传入函数指针代替原来的equality运算符,或运用所谓的function object,这也是STL中find()函数所支持的
-
泛型算法
总共有近75个,常用算法如下
(1) 搜索算法: find(), count(), adjacent_find(), find_if(), count_if(), binary_search(), find_first_of()
(2) 排序及次序整理算法:merge(), partial_sort(), partition(), random_shuffle(), reverse(), rotate(), sort()
(3) 复制、删除、替换算法:copy(), remove(), remove_if(), replace(), replace_if(), swap(), unique()
(4) 关系算法:equal(), includes(), mismatch()
(5) 生成与质变算法:fill(), for_each(), generate(), transform()
(6) 数值算法:accmulate(), adjacent_difference(), partial_sum(), inner_product()
(7) 集合算法:set_union(), set_difference()
3.3 所有容器的共通操作
-
所有容器类以及string类的共通操作
(1) equality
==
和inequality!=
运算符, 返回true或false(2) assignment
=
运算符,将某个容器复制给另一个容器(3) empty()在容器无任何元素时返回true,反之返回false
(4) size()返回容器内元素个数
(5) clear()删除所有元素
#include <iostream> #include <vector> using namespace std; enum state{equalVec, emptyVec}; string information[] = {"equal vectors", "empty vector"}; void compare(vector<int> &v1, vector<int> &v2); int main(){ int arr[] = {1, 2, 3}; vector<int> v1(arr, arr + 3); vector<int> v2; compare(v1, v2); return 0; } void compare(vector<int> &v1, vector<int> &v2) { if(v1 == v2){ // equality运算符 cout << information[equalVec] << endl; } if(v1.empty() || v2.empty()){ // empty() cout << information[emptyVec] << endl; } vector<int> t; t = v1.size() > v2.size()? v1 : v2; // assignment运算符 for(int i = 0; i < t.size(); ++i) // size() cout << t[i] << ' '; cout << endl; t.clear(); // clear() cout << "The size of t is " << t.size() << endl; if(t.empty()) cout << information[emptyVec] << endl; }
(6) begin()返回一个iterator,指向容器的第一个元素
(7) end()返回一个iterator,只想容器的最后一个元素的下一个位置
int arr[] = {1, 2, 3}; vector<int> vec(arr, arr + 3); vector<int>::iterator first = vec.begin(); vector<int>::iterator last = vec.end(); for(; first != last; ++first) cout << *first << ' ';
(8) insert()将单一或某个范围内的元素插入容器内
(9) erase()将容器内的单一元素或某个范围内的元素删除
insert()和erase()的具体行为随容器是顺序性容器或关联容器而有所不同
3.4 使用顺序性容器
顺序性容器用于维护一组排列有序、类型相同的元素
-
vector/list/deque
(1) vector以一块连续内存来存放元素,各元素被存储在距离起始点的固定偏移位置上,随机访问效率较高,但插入或删除缺乏效率
(2) list以双向链接存储内容,每个元素包含value、back指针(指向前一个元素)、front指针(指向后一个元素),随机访问效率低,插入或删除效率高(只需设定有限元素的back和front指针即可)
(3) deque已连续内存存储元素,对于最前端与末端的插入和删除操作,效率更高
-
顺序性容器的定义(五种方式)
(1) 产生空的容器
list<int> ilist; vector<int> ivec;
(2) 产生特定大小的容器,各元素被默认初始化
list<int> ilist(1024); // int类型默认值为0 vector<int> ivec(1024);
(3) 产生特定大小的容器,并为每个元素指定初值
list<int> ilist(10, 2); // 10个元素均初始化为2 vector<int> ivec(10, 2);
(4) 通过一对iterator产生容器,这对iterator用于标示一整组作为初值的元素的范围
int arr[] = {1, 2, 3}; vector<int> vec(arr, arr + 2); list<int> ilist(arr, arr + 2); for(int i = 0; i < vec.size(); i++) cout << vec[i] << ' ';
(5) 根据某容器产生新容器,复制原容器的元素作为新容器的初值
int arr[] = {1, 2, 3}; vector<int> vec(arr, arr + 2); vector<int> vec1(vec); for(int i = 0; i < vec1.size(); i++) cout << vec1[i] << ' ';
-
在容器两端的操作
(1)
push_back()
:在末端插入一个元素vector<int> vec; vec.push_back(1);
(2)
pop_back()
:删除最后一个元素,但不会返回元素值vec.pop_back();
(3) list和deque还支持
push_front()
和pop_front()
ilist.push_front(1); // 在首段插入一个元素 ilist.pop_front(); // 删除第一个元素,但不会返回值
(4)
front()
:读取最前端元素的值(5)
back()
:读取末端元素的值 -
插入函数insert()
(1)
iterator insert(iterator pos, elemType value)
将value插入pos之前,返回要给iterator指向被插入的元素
int arr[] = {1, 2, 3}; list<int> ilist(arr, arr + 3); list<int>::iterator it = ilist.begin(); int ival = 12; while(it != ilist.end()){ if(*it >= ival){ ilist.insert(it, ival); // 将ival插入it之前 break; } ++it; } if(it == ilist.end()) ilist.push_back(ival); // 结果为1 2 3 12
(2)
void insert(iterator pos, int count, elemType val)
在pos之前插入count个元素,每个元素的值均为val
int arr[] = {1, 2, 3}; list<int> ilist(arr, arr + 3); list<int>::iterator it = ilist.begin(); int ival = 12, cnt = 4; while(it != ilist.end()){ if(*it >= ival){ ilist.insert(it, cnt, ival); // 将cnt个ival插入it之前 break; } ++it; } if(it == ilist.end()) ilist.insert(it, cnt, ival); // 结果为1 2 3 12 12 12 12
(3)
void insert(iterator1 pos, iterator2 first, iterator2 last)
在pos之前插入[first, last)所标示的各个元素
int arr[] = {1, 2, 3}; list<int> ilist(1); ilist.insert(ilist.end(), arr, arr + 3); // 结果为0 1 2 3
(4)
void insert(iterator pos)
在pos之前插入一个元素,初值为默认值
-
删除函数erase()
(1)
iterator erase(iterator pos)
删除pos所指的元素,返回指向被删除元素的下一个位置的iterator
int arr[] = {1, 2, 3}; list<int> ilist(arr, arr + 3); cout << *ilist.erase(ilist.begin()) << endl; // ilist为2 3, 输出结果为2
(2)
iterator erase(iterator first, iterator last)
删除[first, last)范围内的元素
int arr[] = {1, 2, 3, 4, 5}; list<int> ilist(arr, arr + 5); list<int>::iterator it1 = find(ilist.begin(), ilist.end(), 2); list<int>::iterator it2 = find(ilist.begin(), ilist.end(), 4); list<int>::iterator it = ilist.erase(it1, it2); cout << *it << endl; // ilist变为1 4 5,输出结果为4 // 可能误认为ilist会变为1 5,应注意的是,删除的范围不包含last所指元素
3.5 使用泛型算法
-
使用泛型算法应包含algorithm头文件
#include <algorithm>
-
常用泛型算法
(1)
find()
用于搜索无序集合中是否存在某值,搜索范围由iterator[first, last)标出,若找到目标则返回一个iterator指向该值,否则返回一个iterator指向last
(2)
binary_search()
用于有序集合的搜索,若找到就返回true,反之返回false。对于有序集合
binary_serach()
比find()
效率更高(3)
count()
返回数值相符的元素数目
(4)
serach()
比对某个容器内是否存在某个子序列,若存在则返回一个iterator指向子序列起始处,反之返回iterator指向容器末尾
-
泛型算法的应用
设计is_elem()函数判断val是否位于Fibonacci数列中
#include <iostream> #include <vector> #include <algorithm> using namespace std; template<typename type> bool is_elem(type, vector<type>&); template<typename type> bool grow_vec(type val, vector<type> &vec); template<typename type> void display(type first, type last); int main(){ vector<int> vec; int val[] = {34, 2, 4, 8, 12, 100}; for(int i : val){ if(is_elem(i, vec)) cout << i << " is a member of Fibonacci sequence." << endl; else cout << i << " is not a member of Fibonacci sequence." << endl; display(vec.begin(), vec.end()); } } template<typename type> bool is_elem(type val, vector<type> &vec){ type max_value = vec.empty()? 0 : vec[vec.size() - 1]; if(max_value < val) return grow_vec(val, vec); if(max_value == val) return true; return binary_search(vec.begin(), vec.end(), val); } template<typename type> bool grow_vec(type val, vector<type> &vec) { if(vec.size() < 2) vec.insert(vec.begin(), 2 - vec.size(), 1); while(vec[vec.size()-1] < val) vec.push_back(vec[vec.size()-1] + vec[vec.size() - 2]); return vec[vec.size() - 1] == val; } template<typename type> void display(type first, type last){ for(; first != last; ++first) cout << *first << ' '; cout << endl; }
若不确定传入的vector是否已经过排序,则可将容器复制一份进行排序再调用binary_search(),但实际上这使得复杂度由O(logN)(排序容器binary_serach算法的时间复杂度)变为O(NlogN)(sort算法的时间复杂度)
vector<int> temp(vec.size()); copy(vec.begin(), vec.end(), temp.begin()); sort(temp.begin(), temp.end()); binary_search(temp.begin(), temp.end(), val);
3.6 设计泛型算法
-
设计一个函数,接受用户传入的vector,返回新的vector内含原vector中小于10的所有数值
// 方法1,只能判断小于10,缺乏弹性 vector<int> less_than_10(const vector<int> vec){ vector<int> re; for(int i : vec) if(i <= 10) re.push_back(i); return re; }
// 方法2,可以判断小于x vector<int> less_than_x(const vector<int> vec, int x){ vector<int> re; for(int i : vec) if(i <= x) re.push_back(i); return re; }
允许用户指定不同的比较操作,如大于、小于等,可以用函数去掉原来的less-than运算符
// 方法3,可以进行不同的比较判断 #include <iostream> #include <vector> using namespace std; bool less_than(int a, int b); vector<int> filter(const vector<int> &vec, int x, bool(*compare)(int, int)); void display(const vector<int> &vec); int main() { vector<int> vec(10, 1); vector<int> v1 = filter(vec, 2, less_than); vector<int> v2 = filter(vec, 0, great_than); display(v1); display(v2); return 0; } bool less_than(int a, int b){ return a < b; } bool great_than(int a, int b){ return a > b; } vector<int> filter(const vector<int> &vec, int x, bool(*compare)(int, int)){ vector<int> re; for(int i : vec) if(compare(i, x)) re.push_back(i); return re; } void display(const vector<int> &vec){ for(auto p = vec.begin(); p != vec.end(); ++p) cout << *p << ' '; cout << endl; } // 运行结果 // 1 1 1 1 1 1 1 1 1 1 // 1 1 1 1 1 1 1 1 1 1
用find()代替for循环
// 找到每一个等于val的元素 int count_occurs(const vector<int> &vec, int val){ vector<int>::const_iterator iter = vec.begin(); int cnt = 0; while((iter = find(iter, vec.end(), val)) != vec.end()){ ++cnt; ++iter; // iter不断增加保证每个元素只遍历一次 } return cnt; }
-
function object
(1) function object是一种class的实例对象,这类class对function call运算符做了重载操作
(2) STL定义了一组function object,分为算术运算、关系运算和逻辑运算
1) 六个算术运算:
plus<type>
,minus<type>
,negate<type>
,multiplies<type>
,divides<type>
,modules<type>
2) 六个关系运算:
less<type>
,less_equal<type>
,greater<type>
,greater_equal<type>
,equal_to<type>
,not_equal_to<type>
3) 三个逻辑运算:
logical_and<type>
,logical_or<type>
,logical_not<type>
(3) function object的应用
sort(vec.begin(), vec.end(), great<int>()); // sort()默认使用less-than运算符,若传入great_than function object,vec中元素讲会以降序排列
-
function object adapter
(1) function object less<type>期望外界传入两个值,若第一个值小于第二个则返回true,但本例中每个元素都必须和用户指定的数值比较,只需传入一个值即可,这可以通过将第二个参数绑定至用户指定的数值完成
(2) function object adapter提供了两个binder adapter,能使二元binary function object转化为一元unary function object
1) bind1st将指定值绑定至第一个操作数
2) bind2nd将指定值绑定至第二个操作数
vector<int> filter(const vector<int> &vec, int x, less<int> lt){ vector<int> re; vector<int>::const_iterator iter = vec.begin(); while((iter = find_if(iter, vec.end(), bind2nd(lt, x))) != vec.end()){ // bind2nd将lt的第二个参数绑定为x,返回lt传入find_if函数 re.push_back(*iter); ++iter; } return re; } // find_if接受两个iterator,标示元素的范围,在范围内的元素若调用第三个参数指向函数返回值为true,则find_if返回一个iterator指向该元素
-
泛型化:消除filter()与容器的元素类型以及容器类型的依赖关系
(1) 使用函数模板,将元素类型假如template的声明中
(2) 传入一堆iterator标示原容器的始末,传入一个iterator指示从何处开始复制元素
int main() { int arr[] = {1, 2, 3, 10, 4, 10, 5, 6, 10}; vector<int> vec(arr, arr + 9); int arr1[9]; vector<int> v(9); cout << "filtering integer array for values greater than 8" << endl; filter(arr, arr + 9, arr1, 8, greater<int>()); cout << "filtering integer vector for values less than 8" << endl; filter(vec.begin(), vec.end(), v.begin(), 8, less<int>()); } template <typename InputIterator, typename OutputIterator, typename ElemType, typename Comp> OutputIterator filter(InputIterator first, InputIterator last, OutputIterator at, const ElemType &val, Comp pred){ while((first = find_if(first, last, bind2nd(pred, val))) != last){ cout << "found value: " << *first << endl; *at = *first; ++at; ++first; } return at; }
-
negator adapter
对function object的真伪值取反,not1对unary funciton object的真伪值取反,not2对binary function object的真伪值取反
-
另一种找到容器内所有小于某值的元素的做法
先对元素排序,以find_if()找到第一个大于指定值的元素位置,再删除该位置之后至vector末尾的所有元素
(1) non-template版本
vector<int> sub_vec(const vector<int> & vec, int val) { vector<int> tmp(vec); sort(tmp.begin(), tmp.end()); auto iter = find_if(tmp.begin(), tmp.end(), bind2nd(greater_equal<int>(), val)); tmp.erase(iter, tmp.end()); return tmp; }
(2) 泛型化版本
template <typename InputIterator, typename OutputIterator, typename ElemType, typename Comp> OutputIterator sub_vec(InputIterator first, InputIterator last, OutputIterator at, ElemType val, Comp pred) { sort(first, last, pred); // 传入pred, 使sub_vec可支持less, greater, less_equal, greater_equal四种关系比较操作 auto it = find_if(first, last, not1(bind2nd(pred, val))); // find_if需要将绑定val后的unary function object进行negator操作 while(first != it) *at++ = *first++; return at; } // 测试程序 int main(){ int arr[] = {1, 2, 3, 10, 4, 10, 5, 6, 10}; vector<int> vec(arr, arr + 9); vector<int> v(vec); v.erase(sub_vec(vec.begin(), vec.end(), v.begin(), 6, less_equal<int>()), v.end()); display(v); } // 输出1 2 3 4 5 6
3.7 使用Map
-
map是一对数值,其中key作为索引,value作为数据
-
map的定义及使用
#include <map> #include <string> map<string, int> words; // 统计输入字符串出现的次数 string tword; while(cin >> tword) words[tword]++; // 若不在words中会先被放到map内并默认初始化为0 // 打印所有字符串及其出现次数 map<string, int>::iterator it = words.begin(); for(; it != words.end(); ++it) cout << "keys: " << it->first << " value: " << it->second << endl;
-
map对象有一个名为first的member对应于key,名为second的member对应于value
-
查找map内是否存在某个key的方法
(1) 方法一:直接把key当作索引用
if(words["c"] == 0) cout << "c not in words" << endl;
缺点:被查询的key若不在map内,则会被自动添加进map中,并初始化其value为0
(2) 方法二:利用map的find()函数,将key传入
if(words.find("c") == words.end()) cout << "c not in words" << endl;
(3) 方法三:利用map的count()函数,将key传入
if(words.count("a") == 0) cout << "a not in words" << endl;
任何一个key再map内最多只有一份,故count()函数只会返回0或1,而multimap可储存多份相同的key
3.8 使用Set
-
Set的定义和使用
int arr[] = {1, 3, 2, 2, 1, 4, 2, 3, 0}; set<int> s(arr, arr + 9); // 传入始末iterator初始化set, 默认按照less-than运算符进行排序 auto iter = words.begin(); for(; iter != words.end(); ++iter) cout << *iter << ' '; cout << endl; // 输出0 1 2 3 4
-
使用set的insert()函数为set添加新元素
(1) 添加单一元素, 使用单一参数的insert()
int val = 2; s.insert(val);
(2) 添加某个范围内的元素,使用双参数的insert()
int arr[] = {1, 3, 2, 2, 1, 4, 2, 3, 0}; s.insert(arr, arr + 9);
3.9 使用Iterator Inserter
-
先前对filter()的实现中,将源端容器符合条件的元素通过赋值的方式加入目的端容器中,通过定义和源端容器同样大小的目的端容器保证不会溢出
while((first = find_if(first, last, bind2nd(pred, val))) != last){ cout << "found value: " << *first << endl; *at++ = *first++; }
缺点:大部分情况下,目的端容器的大小太大
-
与复制有关的泛型算法,copy(), copy_backwards()等,接受一个iterator,均使用赋值复制元素,此后iterator递增至下个位置,但都必须保证目的端容器足够大
-
insertion adapter
(1) **back_inserter()以容器的push_back()**函数取代assignment运算符,传入back_insert()的参数即容器本身
vector<int> result_vec; unique_copy(ivec.begin(), ivec.end(), back_inserter(result_vec));
(2) inserter()一容器的insert()函数取代assignment运算符,接受两个参数,一个是容器,另一个是itereator指向插入操作的起点
vector<int> result_vec; unique_copy(ivec.begin(), ivec.end(), inserter(result_vec, result_vec.end()));
(3) front_inserter()会以容器的push_front()函数取代assignment运算符,只适用于list和deque
list<int> ilist_clone; copy(ilist.begin(), ilist.end(), front_inserter(ilist_clone));
使用insertion adapter必须包含iterator头文件
#include <iterator> template <typename InputIterator, typename OutputIterator, typename ElemType, typename Comp> OutputIterator filter(InputIterator first, InputIterator last, OutputIterator at, const ElemType &val, Comp pred){ while((first = find_if(first, last, bind2nd(pred, val))) != last){ cout << "found value: " << *first << endl; *at++ = *first++; // 传入back_inserter()后,遇到赋值运算回自动地以容器的push_back()代替赋值运算符 } return at; } int main() { int arr[] = {1, 2, 3, 10, 4, 10, 5, 6, 10}; vector<int> vec(arr, arr + 9); vector<int> v(1, 0); // 目的端容器最初有一个元素,值为0 filter(vec.begin(), vec.end(), back_inserter(v), 8, less<int>()); // 调用filter时传入back_inserter(v) display(v); } // 输出结果为0 1 2 3 4 5 6
3.10 使用iostream Iterator
-
从标准输入设备读取一串string,将其存入vector中,并进行排序,最后将字符串写回标准输出设备
#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; int main(){ string word; vector<string> text; while(cin >> word) text.push_back(word); sort(word.begin(), word.end()); for(string i : text) cout << i << ' '; cout << endl; }
-
iostream iterator类,istream_iterator和ostream_iterator分别支持单一元素的读取和写入
#include <iostream> #include <string> #include <vector> #include <algorithm> #include <iterator> int main(){ vector<string> text; istream_iterator<string> is(cin); // 将is定义为绑定至标准输入设备的istream_iterator istream_iterator<string> eof; // 之要定义时不指定istream对象,即代表定义文件末尾EoF copy(is, eof, back_inserter(text)); sort(text.begin(), text.end()); ostream_iterator<string> os(cout, " "); // 第二个参数为分隔符, 默认为'' copy(text.begin(), text.end(), os); }
-
读写文件
将istream_iterator绑定至ifstream object,将osteram_iterator绑定至ofstream object即可
#include <string> #include <vector> #include <algorithm> #include <iterator> #include <fstream> using namespace std; int main(){ vector<string> text; ifstream infile("in.txt"); ofstream outfile("out.txt"); if(! infile){ cerr << "file does not exist" << endl; return -1; } istream_iterator<string> is(infile); // 将istream_iterator绑定至infile istream_iterator<string> eof; copy(is, eof, back_inserter(text)); sort(text.begin(), text.end()); ostream_iterator<string> os(outfile, " "); // outstream_iterator绑定至outfile copy(text.begin(), text.end(), os); }