第九十九章 重点记录/课后习题重点记录
1.第一章的重点及练习
2.第二章的重点及练习
3.第三章的重点及练习
-
头文件中不应该包含using声明。这样使用了该头文件的源码也会使用这个声明,会带来风险。
-
字符串字面值和string是不同的类型。
-
str[x],[]输入参数为string::size_type类型,给出int整型也会自动转化为该类型 ,数组下标的类型:size_t
-
但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。
-
初始化:char input_buffer[buffer_size];,长度必须是const表达式,或者不写,让编译器自己推断。
-
使用数组时,编译器一般会把它转换成指针。
-
标准库类型限定使用的下标必须是无符号类型,而内置的下标可以处理负值。
-
在表达式中使用数组名时,名字会自动转换成指向数组的第一个元素的指针。
-
下面的程序有何作用?它合法吗?如果不合法?为什么?不合法。使用下标访问空字符串是非法的行为。
|
|
-
将标点符号去除后输出字符串剩余的部分。关键代码if (!ispunct(x))
-
下面的范围for语句合法吗?如果合法,c的类型是什么? 要根据for循环中的代码来看是否合法,c是string 对象中字符的引用,s是常量。因此如果for循环中的代码重新给c赋值就会非法,如果不改变c的值,那么合法。
|
|
- 下列的vector对象各包含多少个元素?这些元素的值分别是多少?
|
|
- 在100页的二分搜索程序中,为什么用的是
mid = beg + (end - beg) / 2, 而非mid = (beg + end) / 2 ;? 因为两个迭代器相互之间支持的运算只有-,而没有+。 但是迭代器和迭代器差值(整数值)之间支持+。
|
|
假定p1 和 p2 都指向同一个数组中的元素,则下面程序的功能是什么?什么情况下该程序是非法的?
|
|
解:
将 p1 移动到 p2 的位置。任何情况下都合法。
4
求值顺序:int i = f1() + f2() 先计算f1() + f2(),再计算int i = f1() + f2()。但是f1和f2的计算先后不确定 但是,如果f1、f2都对同一对象进行了修改,因为顺序不确定,所以会编译出错,显示未定义
取余运算m%n,结果符号与m相同
短路求值:逻辑与运算符和逻辑或运算符都是先求左侧运算对象的值再求右侧运算对象的值,当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧运算对象的值。先左再右
小技巧,声明为引用类型可以避免对元素的拷贝,如下,如string特别大时可以节省大量时间。
vector
赋值运算符满足右结合律,这点和其他二元运算符不一样。 ival = jval = 0;等价于ival = (jval = 0);
复合赋值运算符,复合运算符只求值一次,普通运算符求值两次。(对性能有一点点点点影响) 任意复合运算符op等价于a = a op b;
iter++等价于(iter++),递增优先级较高
ptr->mem等价于(ptr).mem ,注意.运算符优先级大于,所以记得加括号
可以嵌套使用,右结合律,从右向左顺序组合
finalgrade = (grade > 90) ? “high pass” : (grade < 60) ? “fail” : “pass”; //等价于 finalgrade = (grade > 90) ? “high pass” : ((grade < 60) ? “fail” : “pass”); 输出表达式使用条件运算符记得加括号,条件运算符优先级太低。
有符号数负值可能移位后变号,所以强烈建议位运算符仅用于无符号数。
逗号运算符从左向右依次求值,左侧求值结果丢弃,逗号运算符结果是右侧表达式的值。
5.
C++语言没有明确规定大多数二元运算符的求值顺序,给编译器优化留下了余地。这种策略实际上是在代码生成效率和程序潜在缺陷之间进行了权衡,你认为这可以接受吗?请说出你的理由。 可以接受。C++的设计思想是尽可能地“相信”程序员,将效率最大化。然而这种思想却有着潜在的危害,就是无法控制程序员自身引发的错误。因此 Java 的诞生也是必然,Java的思想就是尽可能地“不相信”程序员。
|
|
|
|
|
|
|
|
|
|
|
|
6.
|
|
7
|
|
|
|
8.IO库
|
|
|
|
|
|
|
|
|
|
9
const_iterator 可以读取元素但不能修改元素的迭代器类型
C c1(c2);或C c1 = c2; 构造c2的拷贝c1
使用非成员版本的swap是一个好习惯。
当我们用一个对象去初始化容器或者将对象插入到容器时,实际上放入的是对象的拷贝。
emplace开头的函数是新标准引入的,这些操作是构造而不是拷贝元素。
会改变容器大小,不适用于array。 forward_list有特殊版本的erase forward_list不支持pop_back vector和string不支持pop_front
reverse_iterator 按逆序寻址元素的迭代器 const_reverse_iterator 不能修改元素的逆序迭代器 c.rbegin(), c.rend() 返回指向c的尾元素和首元素之前位置的迭代器 c.crbegin(), c.crend() 返回const_reverse_iterator
迭代器 迭代器范围:begin到end,即第一个元素到最后一个元素的后面一个位置。 左闭合区间:[begin, end)
容器操作可能使迭代器失效 在向容器添加元素后: 如果容器是vector或string,且存储空间被重新分配,则指向容器的迭代器、指针、引用都会失效。 对于deque,插入到除首尾位置之外的任何位置都会导致指向容器的迭代器、指针、引用失效。如果在首尾位置添加元素,迭代器会失效,但指向存在元素的引用和指针不会失效。 对于list和forward_list,指向容器的迭代器、指针和引用依然有效。 在从一个容器中删除元素后: 对于list和forward_list,指向容器其他位置的迭代器、引用和指针仍然有效。 对于deque,如果在首尾之外的任何位置删除元素,那么指向被删除元素外其他元素的迭代器、指针、引用都会失效;如果是删除deque的尾元素,则尾后迭代器会失效,但其他不受影响;如果删除的是deque的头元素,这些也不会受影响。 对于vector和string,指向被删元素之前的迭代器、引用、指针仍然有效。 注意:当我们删除元素时,尾后迭代器总是会失效。 注意:使用失效的迭代器、指针、引用是严重的运行时错误! 建议:将要求迭代器必须保持有效的程序片段最小化。 建议:不要保存end返回的迭代器。
定义在stack头文件中。 stack默认基于deque实现,也可以在list或vector之上实现。
定义在stack头文件中。 stack默认基于deque实现,也可以在list或vector之上实现。
有时可能希望操作可以接受更多的参数。
lambda表达式表示一个可调用的代码单元,可以理解成是一个未命名的内联函数。
形式:[capture list](parameter list) -> return type {function body}。
其中capture list捕获列表是一个lambda所在函数定义的局部变量的列表(通常为空)。不可忽略。 return type是返回类型。可忽略。 parameter是参数列表。可忽略。 function body是函数体。不可忽略。 auto f = [] {return 42;}
只读算法 只读取范围中的元素,不改变元素。 如 find和 accumulate(在numeric中定义,求和)。 find_first_of,输入:两对迭代器标记两段范围,在第一段中找第二段中任意元素,返回第一个匹配的元素,找不到返回第一段的end迭代器。 通常最好使用cbegin和cend。 equal:确定两个序列是否保存相同的值。
隐式捕获:让编译器推断捕获列表,在捕获列表中写一个&(引用方式)或=(值方式)。auto f3 = [=] {return v1;}