???? C++ Primer 0x03 学习笔记
3.1 命名空间的 using 声明
- 使用 using 声明可以免去命名空间前缀
- 每个名字都需要独立的 using 声明
- 头文件不应该包含 using 声明,如果头文件里用了 using 声明,那么引用他的文件也会用 using 声明
3.2 标准库类型 string
- 使用等号是拷贝初始化,不用等号是直接初始化
-
cin
>>读入 string
对象,string
对象会自动忽略开头的空白(空格符、换行符、制表符等)并从第一个真正的字符开始读起,知道遇到下一处空白 -
getline
会把换行符读入,但不存进 string
。因为不包含换行符,所以我们有时候要手动加上换行操作符 endl
结束当前行并刷新 -
string
的 size
函数返回 string::size_type
类型,是一个无符号整数,注意不要和有符号数混用。例如:如果n是个负的 int,那么 s.size() < n 永远为真,因为会转化为无符号整型自动取模 - 字符串字面值对象不是
string
对象 -
string
对象可以相加,string
对象也可以和字符串字面值对象相加,但是必须保证每个 + 号两侧至少有一个对象是 string
- 使用基于范围的
for
语句 处理每个字符,如果要改变字符串的字符,那么必须把循环变量定义成引用类型 - 可以使用下标运算符访问某个位置的字符,如果超出范围会造成位置结果,而且由于 s.size() 是无符号整数,因此要下标的计算结果是否可能负数
- 下标访问空字符串是非法的
3.3 标准库类型 vector
-
vector
是类模板,而不是类型 - 不存在引用的
vector
,存的得是对象 - 可以只提供
vector
对象容纳的元素数量而不用略去初始值 - 圆括号,可以说提供的值使用来构造对象的
- 花括号,想列表初始化该对象爱那个,尽量把花括号里的值当成元素初始值的列表来处理,如果无法执行列表初始化,会考虑其他初始化方式。如果是花括号内的,又没法初始化,会考虑用这个值构造对象或者默认值初始化
- 通常情况下,创建
vector
对象的时候直接指定容量并不会比动态添加快,甚至更慢 - 范围
for
语句体内不应改变其遍历序列的大小 - 要使用
size_type
,需要首先指定它是由哪种类型定义的。vector
对象的类型总是包含着元素的类型 - 只有当元素的值可比较的时候,
vector
对象才能被比较,以字典顺序比较 -
vector
下标 0 到 vec.size()-1
- 不能用下标形式添加元素,只能对确知已存在的元素执行下标操作
3.4 迭代器介绍
- 迭代器有
begin
和end
成员,end
成员指示的是尾元素的下一个元素。如果容器为空,begin
和end
返回同一个迭代器,都是尾后迭代器 - 迭代器可以进行解引用操作,尾后迭代器和非法迭代器不可以
- 所有迭代器都支持 == 和 != 但大多数没定义 <,因此要养成迭代器和!=的习惯
-
iterator
和 const_iterator
可以表示迭代器类型,begin
和 end
返回的迭代器类型由对象是否是常量决定,cbegin
和 cend
一定会得到 const_iterator
- 箭头运算符把解引用和成员访问操作结合到一起
- 但凡使用了迭代器的循环体,都不要向迭代器所属的容器添加元素
- 两个迭代器相减得到两个迭代器的距离,类型是
difference_type
的带符号整数。两个迭代器不能相加,注意运算顺序。 - 迭代器和下标互相转换其实就是
begin()
+下标
3.5 数组
3.5.1 定义和初始化数字
- 如果不清楚元素的确切个数,请使用
vector
- 数组维度应该在编译的时候知道,所以维度应该是个常量表达式
- 和内置类型一样,如果在函数内部定义了某种内置类型的数组,那么默认初始化会令数组含有未定义的值
- 定义数组的时候必须指定数组类型,不允许用
auto
关键字 由初始值的列表推断类型 - 数组的元素应为对象,不存在引用的数组
- 使用字符串字面值对字符数组初始话的时候,要记住结尾还有个空字符,所以大小至少要为显示字符数+1
- 数组不允许拷贝和赋值,有的编译器扩展支持,但这不是标准
- 要想理解数组声明的含义,最好的办法就是从数组的名字开始从内到外顺序阅读
3.5.2 访问数组元素
- 在使用数组下标的时候通向将其定义为
size_t
类型(机器相关的无符号类型 - 数组也可以使用 范围 for 循环语句
- 下标应该>=0 而且<数组大小
- 访问非法内存可能造成缓冲区溢出等问题
3.5.3 指针和数组
- 在很多用到数组指针名字的地方,编译器会自动将其换成数组首元素的指针
- 指针也是迭代器
- 使用函数
begin()
和end()
并把数组作为他们的参数可以获得类成员函数begin()
、end()
类似的效果 - 两指针相减是一种
ptrdiff_t
的带符号类型,两个空指针也允许相减,结果为0 - 数组使用的下标运算是C++ 内置的,不是无符号类型,可以处理负数。这与
vector
和 string
是不一样的,标准库类型限定使用的下标必须是无符号类型
3.5.4 C风格字符串
- C风格字符串(字符串字面值)不是一种类型,只是一种约定俗成的写法。按此习惯书写的字符串存放在字符数组中,并以空字符结束,一般利用指针操作
- 很多C风格字符串的函数不会检查字符串参数(例如不会看有没有空字符结束),调用的时候还要仔细思考目标字符串的大小
- 对大多数应用来说,使用标准库
string
要比使用 C风格字符串更安全、更高效
3.5.5 与旧代码的接口
- 尽量使用标准库类型而非数组
- 任何出现字符串字面值的地方都可以用空字符结束的字符数组替代
- 如果程序某处需要 C风格字符串,无法直接使用
string
对象来代替它。例如不能用string
对象直接初始化指向字符的指针,不过可以用 c_str
函数来完成(返回一个C风格的字符串),如果后续改变了string
对象的值,之前返回的数组可能失效,所以要拷贝一份 -
vector
对象允许使用数组初始化,只需要指定拷贝区域的首元素地址和尾元素地址即可 -
string
和vector
往往可以兼容数组,但是反过来不行
3.6 多维数组
- 严格来说,C++ 没有多为数组,平常说的多维数组其实是数组的数组
- 可以使用下标运算来访问多维数组的元素。如果下标运算符数量和维度一样多,那么返回对应元素;如果下标运算符数量小于维度,那么返回内层数组
- 可以使用范围 for 语句处理多维度数组,注意除了最内层的循环外,其他所有循环的控制变量都应该是引用类型的,避免数组被自动转成指针
- 定义指向多维数组的名字时,也会将其转为数组首元素的指针,所以别忘了这个多为数组实际上是数组的数组
- 可以使用类型别名简化多为数组的指针