"); //-->
第八章 IO库
P278-P290
C++语言不直接处理输入输出,而是通过一组定义在标准库中的类型来处理IO。
iostream处理控制台IO
fstream处理命名文件IO
stringstream完成内存string的IO
ifstream和istringstream继承自istream
ofstream和ostringstream继承自ostream
8.1 IO类
(1)IO对象无拷贝或复制。
进行IO操作的函数通常以引用方式传递和返回流。
(2)刷新输出缓冲区
flush刷新缓冲区,但不输出任何额外的字符;
ends向缓冲区插入一个空字符,然后刷新缓冲区。
8.2 文件输入输出
类 作用
ifstream 从一个给定文件读取数据
ofstream 从一个给定文件写入数据
fstream 读写给定文件
8.3 string流
类 作用
istringstream 从string读取数据
ostringstream 向string写入数据
stringstream 既可从string读数据也可以向string写数据
// will hold a line and word from input, respectively string line, word; // will hold all the records from the input vector<PersonInfo> people; // read the input a line at a time until end-of-file (or other error) while (getline(is, line)) { PersonInfo info; // object to hold this record's data istringstream record(line); // bind record to the line we just read record >> info.name; // read the name while (record >> word) // read the phone numbers info.phones.push_back(word); // and store them people.push_back(info); // append this record to people } // for each entry in people for (vector<PersonInfo>::const_iterator entry = people.begin(); entry != people.end(); ++entry) { ostringstream formatted, badNums; // objects created on each loop // for each number for (vector<string>::const_iterator nums = entry->phones.begin(); nums != entry->phones.end(); ++nums) { if (!valid(*nums)) { badNums << " " << *nums; // string in badNums } else // ``writes'' to formatted's string formatted << " " << format(*nums); } if (badNums.str().empty()) // there were no bad numbers os << entry->name << " " // print the name << formatted.str() << endl; // and reformatted numbers else // otherwise, print the name and bad numbers cerr << "input error: " << entry->name << " invalid number(s) " << badNums.str() << endl; }
第九章 顺序容器
P292-P332
顺序容器为程序员提供了控制元素存储和访问顺序的能力。
9.1 顺序容器概述
类型 作用
vector 可变数组大小。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢。
deque 双端队列。支持快速随机访问。在头尾位置插入/删除速度很快。
list 双向链表。只支持双向顺序访问。在list中任何位置进行插入/删除操作速度都很快。
forward_list 单向链表。只支持单向顺序访问。在链表任何位置进行插入/删除操作速度都很快。
array 固定大小数组。支持快速随机访问。不能添加或删除元素。
string 与vector相似的容器,但专门用于保存字符、随机访问快。在尾部插入/删除速度快。
9.2 容器库概述
一般,每个容器都定义在一个头文件中。
容器均定义为模板类。
类型 别名
iterator 此容器类型的迭代器类型
const_iterator 可以读取元素,但不能修改元素的迭代器类型
size_type 无符号整数类型,足够保存此种容器类型最大可能容器的大小
difference_type 带符号整数类型,足够保存两个迭代器之间的距离
value_type 元素类型
reference 元素的左值诶性:与value_type&含义相同
const_reference 元素的const左值类型(即,const value_type&)
构造函数
C c; 默认构造函数,构造空容器
C c1(c2) 构造c2的拷贝c1
C c(b, e) 构造c,将迭代器b和e指定的范围内的元素拷贝到c(array不支持)
C c{a, b, c...} 列表初始化c
赋值与swap
c1=c2 将c1中的元素替换为c2中元素
c1 = {a, b, c...} 将c1中的元素替换为列表中元素(不适用于array)
a.swap(b) 交换a和b的元素
swap(a, b) 与a.swap(b)等价
大小
c.size() c中元素的数组(不支持forward_list)
c.max_size() c中可保存的最大元素数目
c.empty() 若c中存储了元素,返回false,否则返回true
添加/删除元素(不适用于array)
c.insert(args) 将args中的元素拷贝进c
c.emplace(inits) 使用inits构造c中的一个元素
c.erase(args) 删除args指定的元素
c.clear() 删除c中的所有元素,返回void
关系运算符
==, != 所有容器都支持相等(不等运算符)
<,<=,>,>= 关系运算符(无序关联容器不支持)
获取迭代器
c.begin(), c.end() 返回指向c的首元素和尾元素之后位置的迭代器
c.cbengin(),c.cend() 返回const_iterator
反向容器的额外成员(不支持forward_list)
reverse_iterator 按逆序寻址元素的迭代器
const_reverse_iterator 不能修改元素的逆序迭代器
c.rbegin(), c.rend() 返回指向c的尾元素和首元素之前位置的迭代器
c.crbegin(), c.crend() 返回const_reverse_iterator
(1)迭代器
标准库的迭代器允许我们访问容器中的元素,所有迭代器都是通过解引用运算符来实现这个操作。
一个迭代器返回由一对迭代器表示,两个迭代器分别指向同一个容器中的元素或者是尾元素之后的位置。它们标记了容器中元素的一个范围。
左闭合区间:[begin, end)
while (begin !=end){ *begin = val; ++begin; }
(2)容器类型成员
见概述
通过别名,可以在不了解容器中元素类型的情况下使用它。
(3)begin和end成员
begin是容器中第一个元素的迭代器
end是容器尾元素之后位置的迭代器
(4)容器定义和初始化
P290
C c; // 默认构造函数 C c1(c2) C c1=c2 C c{a,b,c...} // 列表初始化 C c={a,b,c...} C c(b,e) // c初始化为迭代器b和e指定范围中的元素的拷贝 // 只有顺序容器(不包括array)的构造函数才能接受大小参数 C seq(n) C seq(n,t)
将一个容器初始化为另一个容器的拷贝:
当将一个容器初始化为另一个容器的拷贝时,两个容器的容器类型和元素类型都必须相同。
不过,当传递迭代器参数来拷贝一个范围时,就不要求容器类型相同,只要能将要拷贝的元素转换为要初始化的容器的元素类型即可。
标注库array具有固定大小:
不能对内置数组类型进行拷贝或对象赋值操作,但array并无此限制。P301
(5)赋值与swap
arrray类型不允许用花括号包围的值列表进行赋值。
array<int, 10> a2={0}; //所有元素均为0 s2={0}; // 错误!
seq.assign(b,e) // 将seq中的元素替换为迭代器b和e所表示的范围中的元素。迭代器b和e不能指向seq中的元素。
swap用于交换2个相同类型容器的内容。调用swap之后,两个容器中的元素将交换。
(6)容器大小操作
size 返回容器中元素的数目
empty 当size为0返回布尔值true,否则返回false
max_size 返回一个大于或等于该类型容器所能容纳的最大元素数的值
(7)关系运算符
关系运算符左右两边的元素符对象必须是相同类型的容器。
::: tip
只有当元素类型也定义了相应的比较运算符,才可以使用关系元素安抚来比较两个容器
:::
9.3 顺序容器操作
(1)向顺序容器添加元素
表格P305
使用push_back:追加到容器尾部
使用push_front:插入到容器头部
在容器中的特定位置添加元素:使用insert
vector <string> svec; svec.insert(svec.begin(), "Hello!");
插入范围内元素:使用insert
使用emplace操作:
emplace_front、emplace和emplace_back分别对应push_front、insert和push_back。
emplace函数直接在容器中构造函数,不是拷贝。
(2)访问元素
P309
注意end是指向的是容器尾元素之后的元素。
在顺序容器中访问元素的操作
c.back() 返回c中尾元素的引用。若c为空,函数行为未定义
c.front() 返回c中首元素的引用。若c为空,哈数行为未定义
c[n] 返回c中下标为n的元素的引用,n是一个无符号整数。若n>=size(),则函数行为未定义
c.at[n] 返回下标为n的元素的引用。如果下标越界,则抛出out_of_range异常
(3)删除元素
顺序容器的删除操作
c.pop_back() 删除c中尾元素。若c为空,则函数行为未定义。返回返回void
c.pop_front() 删除c中首元素。若c为空,则函数行为未定义。返回void
c.erase(p) 删除迭代器p所指定的元素,返回一个指向被删除元素之后元素的迭代器,如p指向尾元素,则返回尾后(off-the-end)迭代器。若p是尾后迭代器,则函数行为未定义
c.erase(b, e) 删除迭代器b和e所指定范围内的元素。返回一个指向最后一个被删除元素之后元素的迭代器。若e本身就是尾后迭代器,则函数也返回尾后迭代器
c.claer() 删除c中的所有元素。返回void
(4)特殊的forwar_list操作
P313
befor_begin();cbefore_begin();insert_after;emplace_after;erase_after;
(5)改变容器大小
reseize用于扩大或者缩小容器。
resize操作接受一个可选的元素值参数,用来初始化添加到容器内的元素。
如果容器保存的是类类型元素,且resize向容器中添加新元素,则必须提供初始值,或者元素类型必须提供一个默认构造函数。
9.4 vector对象是如何增长的
为了避免影性能,标准库采用了可以减少容器空间重新分配次数的策略。当不得不获取新的内存空间时,vector和string通常会分配比新的新的空间需求更大的内存空间。容器预留这些空间作为备用,可以用来保存更多的新元素。
容器管理的成员函数:
容器大小管理操作
c.shrink_to_fit() 请将capacity()减少为与size()相同大小
c.capacity() 不重新分配内存空间的话,c可以保存多少元素
c.reverse() 分配至少能容纳n个元素的内存空间。reverse并不改变容器中元素的数量,它仅影响vector预先分配多大的内存空间。调用reverse永远不减少容器占用的内存空间。
capcacity和size:
区别:
容器的size是指它已经保存的元素的数目;
capcacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。
注意:只有当迫不得已时才可以分配新的内存空间。
9.5 额外的string操作
(1)构造string的其他方法
构造string的其他方法
string s(cp, n) s是cp指向的数组中前n个字符的拷贝
string s(s2, pos2) s是string s2从下标pos2开始的字符的拷贝。
string s (s2, pos2, len2) s是string s2从下标pos2开始len2个字符的拷贝
substr操作:
substr操作返回一个string,它是原始string的一部分或全部的拷贝。
s.substr(pos, n) 返回一个string,包含s中从pos开始的n个字符的拷贝。pos的默认值为0。n的默认值为s.size() - pos, 即拷贝从pos开始的所有字符
(2)改变string的其他方法
assign 替换赋值,总是替换string中的所有内容
insert 插入
append 末尾插入,总是将新字符追加到string末尾
replace 删除再插入
(3)string搜索操作
string搜索操作
s.find(args) 查找s中args第一次出现的位置
s.rfind(args) 查找s中args最后一次出现的位置
s.find_first_of(args) 在s中查找args中任何一个字符第一次出现的位置
s.find_last_of(args) 在s中查找args中任何一个字符最后一次出现的位置
s.find_first_not_of(args) 在s中查找第一个不在args中的字符
s.find_last_not_of(args) 在s中查找最后一个不在args中的字符
(4)compare函数
compare有6个版本,P327
(5)数值转换
P328
tostring
stod
9.6 容器适配器
顺序容器适配器:
stack; queue; priority_queue;
适配器是一种机制,能使某种事物看起来像另外一种事物。
定义一个适配器:
适配器有2个构造函数:
1、默认构造函数创建一个空对象
2、接受一个容器的构造函数
栈适配器:
栈的操作
s.pop() 删除栈顶元素,但不返回该元素值
s.push(item) 创建一个新元素压入栈顶,该元素通过拷贝或移动item而来,或者由args构造
s.emplace(args) 由arg构造
s.top() 返回栈顶元素,但不将元素弹出栈
队列适配器:
queue和priority_queue操作
q.pop() 返回queue的首元素或priority_queue的最高优先级的元素,但不删除此元素
q.front() q.back() 返回首元素或尾元素,但不删除此元素。只适用于queue
q.top() 返回最高优先级元素,但不删除该元素。只适用于priority_queue
q.push(item) q.empalce(args) 在queue末尾或priority_queue中恰当的位置创建一个元素,其值为item,或者由args构造
术语
begin容器操作:返回一个指向容器首元素的迭代器,如果容器为空,则返回尾后迭代器。是否返回const迭代器依赖于容器的类型。
cbegin容器操作:返回一个指向容器尾元素之后的const_iterator。
第十章 泛型算法
P336-P371
标准库并未给每个容器添加大量功能,而是提供了一组算法。这些算法是通用的,可以用于不同类型的容器和不同类型的元素。
10.1 概述
头文件:algorithm、numeric
算法不依赖于容器,但算法依赖于元素类型的操作。
10.2 初识泛型算法
(1)只读算法
accumulate 求和
equal 是否相等
(2)写容器元素的算法
算法不检查写操作
拷贝算法:copy
重排容器元素的算法:sort
::: tip
标准库函数对迭代器而不是容器进行操作。因此,算法不能直接添加或删除元素
:::
10.3 定制操作
标准库允许我们提供自己定义的操作来代替默认运算符。
(1)向算法传递函数
谓词:
谓词是一个可调用的表达式,其返回结果是一个能用作条件的值。
标准库算法的谓词分为两类:
1、一元谓词:只接受单一参数。
2、二元谓词:接受两个参数。
bool isShorter(const string &s1, const string &s2) { retrun s1.size() < s2.size(); } sort(words.begin(), words.end(), isShorter);
排序算法:
stable_sort算法维持相等元素的原有顺序。
(2)lambda表达式
lamba:
lambda表达式表示一个可调用的代码单元。一个lambda具有一个返回类型、一个参数列表和一个函数体。
[capture list](parameter list) -> return type {function body} // capture list 捕获列表,lambda所在函数中定义的局部变量 // 捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和在它所在函数之外声明的名字 // lambda必须使用尾置返回来指定返回类型
(3)lambda捕获和返回
两种:值捕获、引用捕获
::: warnning
当以引用方式捕获一个变量时,必须保证在lambda执行时变量是存在的。
一般的,应该尽量减少捕获的数据量,来避免潜在的问题。
如果可能,避免捕获指针或引用。
:::
隐式捕获:
当混合使用隐式捕获和显式捕获时,捕获列表中的第一个元素必须是一个&或=。显式捕获的变量必须使用与隐式捕获不同的方式。
lambda捕获列表 P352
可变lambda:
若希望改变一个被捕获的变量的值,必须在参数列表首加上关键字mutable。
指定lambda返回类型:
当需要为lambda定义返回类型时,必须使用尾置返回类型。
(4)参数绑定
标准库bind函数:
auto newCallable = bind(callable, arg_list); // 调用newCallable时,newCallable会调用callable,并传递给它arg_list中的参数
10.4 再探迭代器
插入迭代器、流迭代器、反向迭代器、移动迭代器
(1)插入迭代器
back_inserter:创建一个使用push_back的迭代器
front_inserter:创建一个使用push_front的迭代器
inserter:创建一个使用inserter的迭代器
(2)iostream迭代器
istream_iterator 读取输入流
ostream_iterator 向一个输出流写数据
istream_iterator操作:
istream-iterator操作
istream_iterator<T> in(is);in从输入流is读取类型为T的值
istream_iterator<T> end;读取类型为T的值得istream_iterator迭代器,表示尾后位置
in1 == in2 in1 != in2;in1和in2必须读取相同类型。如果它们都是尾后迭代器,或绑定到相同的输入,则两者相等
*in 返回从流中读取的值
in->mem 与(*in).mem含义相同
++in, in++ 用>>从输入流读取下一个值
ostream_iterator操作:
ostream_iterator操作
ostream_iterator<T> out(os); out将类型为T的值写到输出流os中
ostream_iterator<T> out(os, d); out将类型为T的值写到输出流os中,每个值后面都输出一个d。d指向一个空字符串结尾的字符数组
out = val 用<<将val写入到out所绑定的ostream中
*out, ++out, out++
(3)反向迭代器
反向迭代器就是在容器中从尾元素向首元素反向移动的迭代器。
10.5 泛型算法结构
10.6 特定容器算法
对于list、forward_list,应该优先使用成员函数的算法而不是通用算法。
术语
cref标准库函数:返回一个可拷贝的对象,其中保存了一个指向不可拷贝类型的const对象的引用
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。