1.三种流类型:
为了操作wchar_t类型,标准库又定义了w开头的wiostream、wfstream、wstringstream等类型,可以使用wcin、wcout等进行输入和输出工作。
2. IO对象不允许复制或者赋值,所以只能传递它们的引用或者指针。例如:
void myprint(ostream& output, string content) { output<<content; }注意:因为读写IO对象时需要修改对象内部的状态码,所以引用或者指针不能是const的。
3 流的状态码(iostate)包括:(你可以使用rdstate()来读取)
注意:IO对象遇到错误时将进入错误状态,不能继续使用;可以使用clear()函数进行更新状态,重新进行IO操作。
4. IO对象管理着一个缓冲区,用来缓存数据然后一次性输出来提升IO的效率。强制清空缓冲区(输入/输出)有三种方法:使用endl、ends或者flush操作符;使用unitbuf操作符(nounitbuf);或者将输入流与输出流绑定(输入流读取时输出流的缓冲区被强制清空)三种方法。例:
//使用endl ends flush cout<<"test"<<endl; //添加换行符 cout<<"test"<<ends; //添加null cout<<"test"<<flush; //什么也不添加 //使用unitbuf cout<<unitbuf<<"test"<<nounitbuf; //unitbuf刷新缓冲区,nounitbuf恢复系统对缓冲区的管理 //绑定输入流和输出流 cin.tie(&cout); //绑定 cin.tie(0); //解除绑定5. 在c++11中,可以使用string对象创建fstream系列的对象了。(这改进...我该说什么好呢?)
6. 当一个fstream对象被销毁时,它打开的文件会被自动close。
7. stringstream与类型转换:使用stringstream做类型转换的注意了,clear()调用只是清理了流的状态并不是清理了流的缓冲区,str("")(传入一个空串)才能够清空缓冲区。我有个惨痛的经历,有一次需要导入一个几百G的文件,我使用了stringstream做类型转换(string转unsigned long long),没有正确的清理掉stringstream的缓存,导致程序运行到一半就吃光了内存崩溃了。对于stringstream实在头疼的人,可以使用c++11新增的转换函数或者c风格的strtoull()之类的函数代替。
8.标准库的顺序容器包括:vector、list、deque、forward_list和array五种;c++11新增了两种容器,分别是仿照数组的array和仿照单向链表的forward_list。
array<int, 10> arr = {1,2,3,4}; //大小为10的array对象 forward_list<string> fl = {"abc","bcd"}; //单向链表
其中,array的大小不能改变,所以它声明时必须显式的给出大小;同时,array还不支持顺序容器的resize()等调整大小的操作。forward_list是单向链表,它的很多操作都有典型的单向链表特征,与其他顺序容器的使用方法不太一样。
9. vector使用连续存储(数组)实现,高效随机访问,高效尾插入删除,低效头部中间插入删除;list使用链表实现,高效插入删除,低效随机访问;deque使用链表和数组的折中(链接着的多个小数组)实现,高效双端插入删除,较高效随机访问,低效中间插入删除;forward_list使用单向链表实现,高效插入删除,低效访问;array是固定大小的数组,高效访问,不支持插入和删除。
10.迭代器范围:由一对迭代器begin和end所确定的迭代器范围是从begin到end的左闭合区间,即:begin、begin+1、begin+2 ...end-2、end-1。注意,包含begin但不包含end(左闭合的特性)。begin和end必须满足两个条件:
vector<int> ivec1; list<int> ilist; int a[10] = {...}; vector<int> ivec2(ivec1); //ok vector<int> ivec3(ilist); //error vector<int> ivec4(ilist.begin(), ilist.end()); //ok vector<int> ivec5(a, a+10); //ok vector<int> ivec6 = {1,2,3,4,5}; //ok
12. 赋值 assign与swap:赋值和assign会导致左操作数的内容全部被清空,swap交换两个对象的内容左操作数内容没丢失。(其实swap也就相当于交换一下指针,执行相当的快。)另外,在c++11中新增了函数式的swap,行为和成员swap一样,但是更容易让人理解。
13. 顺序容器支持比较操作符(==、!=、<、<=、>和>=):其行为类似string的比较类似,返回第一个不相同的元素的比较结果。所以,使用它们也要求容器内部的对象也支持比较操作符。
14. 在c++11中,顺序容器的insert函数返回新插入的元素的迭代器(下一次插入的位置),方便在循环中连续插入。如果范围insert的输入迭代器范围是空,则返回传入的迭代器(这其实也是下次插入的位置)。
15. c++11新引入了emplace成员函数:emplace(对应insert)、emplace_front(对应push_front)和emplace_back(对应push_back)。它们直接调用构造函数在容器中构造对象,所以调用它们的参数必须与容器元素类型的构造函数一致。这种成员函数的优势在于直接构造,省略了构造临时对象再复制的开销。
class A { public: A(string s, int a, double b):m_s(s),m_a(a),m_b(b){} A(string s):A(s,0,0.0){} A(string s, int a):A(s,a,0.0){} A():A("",0,0.0){} private: string m_s; int m_a; double m_b; } vector<A> v; v.emplace_front("abc",1,3.14); //调用构造函数 v.emplace_back("def"); //同上 v.emplace(v.begin(),"ghi",3); //同上 v.emplace_back(); //调用默认构造函数16. 访问容器中元素的成员函数(front、back、at和下标)返回的是引用,如果容器不是const的,那么可以作为左值放在=号的左边直接修改对应的元素。
vector<int> v = {1,2,3,4}; v.front() = 5; //将v的首元素修改为517. 特别的forward_list:forward_list是单向链表,所以与其他的顺序容器有很多的不同。我们知道,单向链表的所有操作都是作用在当前元素的下一个元素之上,所以forward_list中的成员函数是insert_after、emplace_after和erase_after,为了操作首元素,还提供了返回链表头的before_begin()。
18. size与capacity,resize()与reserve():size是vector容器中已使用空间的大小,capacity是 vector容器中总共空间的大小,size随着插入删除而增加减少,只有容器内容大小超过capacity的时候,vector才会增长,capacity才会变。resize()函数调整size,参数比当前小则删除多余元素,参数比当前大则初始化多余的元素,保证size大小内的元素全 部可用(读写);而reserve则是修改capacity的大小,修改总空间(主要还是备用空间),reserve的参数比原来小的时候不起作用,参数比原来大的时候多出来的空间未初始化(这些元素不可用)。
19. 很多容器操作会导致迭代器失效,所以尽量不要存储迭代器,尤其不要存储end返回的迭代器。
20. vector的自增长:当vector的容量不够用时,容器首先会在内存中重新申请一块大小为原来的x倍(比如说:2倍)的空间,然后将原有的内容全部copy过去,再然后释放原有内存空间,最后将新内容加入。在《算法导论》中,使用均摊分析可以得出,在每次都倍增的情况下,算法的时间复杂度是:O(n) = 3*n。
21. string的find系列的函数在找不到目标时返回string::npos,string::npos是一个static的string::size_type(unsinged),它值是-1(也就是unsigned的最大值)。此外,还有find_first_not_of 和 find_last_not_of 这两个排除查找成员函数,某些时候应该很好用。
22. c++11中引入了多个数值数据与string转换的函数:(泪奔~~太贴心了)
stack<string, vector<string>> svec; //要求使用vector实现的stack此外,注意容器适配器也增加了emplace方法。