第三章:字符串、向量和数组
笔记
1. 头文件不应包含using声明,因为可能不经意间包含时,会造成名字冲突。
2. 如果使用等号(=)初始化一个变量,实际上执行的是拷贝初始化(copy initialization)。如果不适用等号,则执行的是直接初始化(direct initialization)。如:
string s5 = "hiya"; // 拷贝初始化 string s6("hiya"); // 直接初始化 string s7(10, 'c'); // 直接初始化,s7的内容是cccccccccc
3. 在c++11新标准中,允许编译器通过auto或者decltype来推断变量的类型。如:
string line; auto len = line.size(); // len的类型是stirng::size_type
4. 字符串字面值与string是不同的类型。
5. c++11新标准提供一种语句:范围for(range for)语句。形式是:
for (declaration : expression) statement
其中,expression部分是一个对象,用于表示一个序列。declaration部分负责定义一个变量,该变量将被用于访问序列中的基础元素。每次迭代,declaration部分的变量会被初始化为expression部分的下一个元素值。例如:
例一:
string str("some string"); for (auto c : str) // 用str中的每个字符依次去初始化c cout << c << endl; // 输出当前字符,后面紧跟一个换行符
例二:
string s("Hello World); // 转换成大写形式 for (auto &c : s) // 对于s中的每个字符(注意:c是引用) c = toupper(c); // c是一个引用,因此复制语句将改变s中字符的值 cout << s << endl;
6. string使用下标运算符([])访问时,返回值是该位置上字符的引用。如:
string s("some string"); for (decltype(s.size()) index = 0; // 类型推断 index != s.size() && !isspace(s[index]); ++index) // 注意判断的顺序 s[index] = toupper(s[index]); // 将当前字符改写成大写形式
7. 编译器根据模板创建类或函数的过程称为实例化(instantiation),当使用模板时,需要指出编译器应当把类或函数实例化成何种类型。
8. c++11新标准提供了一种为vector对象的元素赋初值的方法,即列表初始化。
vector<string> articles = {"a", "an", "the"};
9. 如果循环体内包含有向vector对象添加元素的语句,则不能使用范围for循环,即范围for语句不应该改变所遍历序列的大小。
10. 要使用size_type,需首先指定它是由哪种类型定义的。如:
vector<int>::size_type // 正确 vector::size_type // 错误
11. 不能使用下标形式添加元素,并且使用下标访问元素要确保元素存在,另一种有效手段是尽可能使用范围for语句。
12. c++程序员更习惯在for循环中使用!=,而非<进行判断,所有标准库容器都定义了==和!=,但是它们中的大多数都没有定义<运算符。
13. begin()和end()返回的具体类型有对象是否是常量决定,常量返回:const_iterator,非常量返回:iterator。此外,c++11新标准引入了两个新函数,分别是cbegin()和cend(),用来返回const_iterator类型。如:
// 依次输出text的每一行直至遇到一个空白行为止 for (auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it) cout << *it << endl;
14. 凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。
15. string和vector都定义了difference_type,因为这个距离可正可负,所以difference_type是带符号类型的。
16. 数组的维度必须是一个常量表达式,如:
unsigned cnt = 42; // 不是常量表达式 constexpr unsigned sz = 42; //常量表达式 int *parr[sz]; //含有42个整型指针的数组 stirng bad[cnt]; //错误:cnt不是常量表达式
17. 要理解数组声明的含义,最好的方法是从数组的名字开始按照由内向外的顺序阅读。
18. 在很多实用数组名字的地方,编译器一般会自动将其替换为一个指向数组首元素的指针。但是,当使用decltype关键字时不会发生转换指针,如定义数组ia[10]后,使用decltype(ia)返回类型是10个元素构成的数组。
19. c++11新标准引入两个名为begin()和end()的函数,在iterator头文件中定义。如:
int ia[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int *beg = begin(ia); // 指向ia首元素的指针 int *last = end(ia); // 指向ia尾元素的下一个位置的指针
20. 两个指针相减的结果是一种名为ptrdiff_t的标准库类型,和size_t一样,ptrdiff_t也是一种定义在cstddef头文件中的机器相关的类型。
21. 尽管c++支持c风格字符串,但是c++程序中最好还是不要使用它们。
22. 使用数组初始化vector对象:
int int_arr[] = {0, 1, 2, 3, 4, 5}; vector<int> ivec(begin(int_arr), end(int_arr));
23. c++中没有多维数组,通常所说的多维数组其实是数组的数组。
24. 要使用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型。这样是为了避免数组被自动转成指针。如:
for (const auto &row : ia) // ia为二维数组 for (auto col : row) cout << col << endl;
术语
拷贝初始化(copy initialization)、直接初始化(direct initialization)、范围for(range for)语句、容器(container)、
类模板(class template)、实例化(instantiation)、迭代器(iterator)、C风格字符串(C-style character string)。
2016-10-27