《C++ Primer》读书笔记 第三章

1.注意:头文件不应包含using声明。因为头文件的内容会拷贝到所有引用他的文件中去,对于某些程序来说,由于不经意间包含了一些名字,可能会产生名字冲突。
2.string类型的读入:用cin读入string,忽略所有的前置空格、换行符、tab等,读入串,在此读到这些特殊字符时结束,读入的串中不包含这些特殊字符。getline读入时,一直到换行符结束。
3.auto len = line.size();此时len的类型是string::size_type,size()函数返回一个无符号整形数,因此size_type是一种无符号整数类型,也可显式调用string::size_type a = 0;切记,在调用size()函数时最好不要用int类型,如果在表达式中混用了带符号类型数和无符号类型数有可能会产生意想不到的结果。
4.字面值和string对象相加:当“+”运算符两端至少有一个是string对象时,字符字面值会自动转换成string对象,但两个都是字符字面值时不可以:string s1 = s + "hehe";//正确string s2 = "he" + "he";//不正确 特殊的string s3 = s + "he" + "he";//正确,因为先计算前两个得到一个string对象,在与第三个计算。
5.使用头文件cname和name.h也有不一样的地方,在名为cname的头文件中定义的名字从属命名空间std,而定义在名为.h的头文件中则不然,因此建议使用cname的形式。
6.注意:string和vector []接收下标的类型是string::size_type和vector::size_type,而不是int,带符号整数可以当作下标时会自动转换成size_type类型。
7.特殊的,定义const string s = "hehehehe"; for (auto& c: s) {} //此时c是const char&类型。
8.C++11的新特性,在C++11中,定义嵌套模版类对象时,两个'>'之间不用再加空格了,要知道在以前的C++版本中是要加空格的。
9.vector:在范围for循环内不能改变其所遍历序列的大小,更不能添加元素,但在非范围的for循环中可以。
10.vector初始化:可以使用花括号或圆括号,如果用圆括号,可以说提供的值是用来构造vector对象的,如果用的是花括号,可以表述称列表初始化,花括号中的元素一般作为元素初始值的列表来处理。另一方面,如果初始化时使用了花括号的形式但是提供的值又不能用来列表初始化,就要考虑用这样的值来构造vector对象了,例如:vector<string> v1{10};//有10个默认初始化的元素。vector<string> v2{10,"hehe"};//有10个值为"hehe"的元素
11.vector一种特殊的赋值方式:vector<int> v; v = {1,2,3};//用列表中的元素代替v中的元素。
12.迭代器一般有两种:iterator和const_iterator,后者为常量迭代器,只能读不能写,如果对象是个常量,则只能用iterator,如果是个变量,即能用iterator又能用const_iterator,只不过后者不能写。
13.容器中的begin和end。begin和end的返回的具体类型由对象是否是常量决定,如果对象是常量,则返回const_iterator,否则返回iterator。为了专门得到const_iterator,C++11新标准引入了两个新函数:cbegin和cend。不论vector对象(或string对象)本身是否是常量,返回值都是const_iterator;
14.任何一种可能改变vector对象容量的操作,比如push_back,都会使该vector对象的迭代器失效。
15.两迭代器的差的类型是名为difference_type的带符号型整数,string和vector都定义了difference_type,因为这个差可正可负,所以是带符号类型的。
16.数组的维度必须是一个常量表达式。另外,定义数组的时候必须指定数组的类别,不允许用auto关键字由初始值的列表推断类型。数组的初始化这里不多说(详见P102,英文版P114)
17.定义数组的指针 int (*p)[10];定义数组的引用 int (&a)[10];特别的int* (&b)[10];b是一个引用,指向一个数组,数组里放了10个指针。
18.在使用数组下标时,通常将其定义为size_t类型,size_t是一机器相关的无符号类型,它被设计的足够大以便能表示内存中任意对象的大小,在cstddef头文件中定义了size_t类型。
19.在函数内定义int a[10];此时数组未初始化,若定义成int a[10]={};则被默认初始化。
20.当使用数组作为一个auto变量的初始值时,推断得到的类型是指针而非数组,但当使用decltype函数时,该函数的返回类型是由10个整数构成的数组。
21.C++11中引入了begin和end函数,也支持数组类型,与容器中的begin和end不同,这两个函数不是成员函数,这两个函数定义在iterator头文件中。
22.这里值得一提的是,若定义一个数组,int a[10]; &a和a的区别是:&a和a都是地址,而且值也相同,但类型不一样,&a是整个数组的地址,而a是数组首元素的地址,因此a与整形指针相容,&a与数组指针相容,&a+1与&a的距离是一个数组的字节数,多维数组也是这样。
23.如果在表达式中含有解引用运算符和点运算符,在必要的地方加上圆括号。 如:(*it).end();
24.如果用整形指针,下标可以为负数,如int a[10]; int *p = a + 2; p[-2] = 1; 虽然标准库类型string和vector也能执行下标运算,但是数组与他们相比还是有所不同,标准库类型限定使用的下标必须是无符号类型,而内置的下标无此要求,内置的下标运算符可以处理负值。
25.在string对象的复合赋值运算中允许使用以空字符结束的字符数组作为右侧的运算对象。
26.若要将string对象的内容赋给一个char*字符串,可以调用string函数c_str(),该函数返回一个字符指针,指向这个string对象的内容,为了确保我们不改变这个字符数组的内容,返回结果为const char*。另外,我们无法保证c_str()函数返回的数组一定有效,事实上,如果后续的操作改变了s的值就可能让之前返回的数组失去效用。
27.vector允许使用数组来初始化vector对象,只需指明要拷贝区域的首元素地址和尾后元素地址就可以了。例如:int a[] = {1,2,3,4,5}; vector<int> v(begin(a),end(a));
28.在多维数组中,如果仅仅想初始化每一行的第一个元素,通过如下的语句即可:int a[3][4]={{0},{3},{4}};
29.使用范围for循环处理多维数组:int a[10][10]; for (auto& row : a) for (auto& col : row) {col=1;},为什么要用引用类型,这里不单单是改变数组元素的缘故,假设写成如下形式:for (auto row : a) for (auto cal : row) {}程序无法通过编译,应该写成如下形式:for (const auto& row : a) for (auto col : row) {} 尽管这个循环中并没有任何写操作,可是我们还是将外层循环的控制变量声明成了引用类型,这是为了避免数组被自动转成指针,像之前一样的第一个循环便利a的所有元素,注意程序元素实际上是大小为4的数组,因为row不是引用类型,所以编译器初始化row时会自动将这些数组形式的元素转换成指向该数组内首元素的指针,这样得到的row的类型就是int*,显然内层的循环就不合法了,编译器将试图在一个int*内遍历,这显然和程序的初衷相去甚远。因此,要使用范围for语句处理多维数组,除了最内层的循环外,其他所以的循环的控制变量都应该是引用类型。

原文地址:https://www.cnblogs.com/Chierush/p/3454990.html