C++ Primer v3
前两天看完了《C++ primer》的第4版,今天刚看完第3版。第3版看得比较粗略。总的感觉是第4版显得比较条理,第3版的细节比较分散。第4版中将很多应该注意的知识点都重点强调了一下,从第3版不好区分哪些比较重点。
第一章 C++概述
1. 编译C++程序时,编译器自动定义了一个预处理器名字__cplusplus.
在编译标准C时,编译器自动定义宏__STDC__。当然,__cplusplus和__STDC__不能被同时定义
第二章 C++浏览
1. C++中的数组
在内置数据类型与标准库类的类型之间是复合类型(compound type)特别是指针和数组,引用类型。
虽然C++对数组提供了内置支持,但是这种支持仅限于“用来读写单个元素”的机制,C++不支持数组的抽象(abstraction),也不支持对整个数组的操作。
数组类型本身没有自我意识,它不知道自己的长度,我们必须另外记录数组本身的这些信息。在C++中,数组不同于整数类型和浮点数类型,它不是C++语言的一等(first-class)公民。数组是从C语言继承过来的,它反映了数据与其进行操作的算法的分离,而这正是过程化程序设计的特征。
2. 静态与动态内存分配
(1)静态对象是有名字的变量,可以直接对其进行操作。而动态对象是没有名字的变量,我们只能通过指针对其进行间接操作。
(2)静态对象的分配与释放是由编译器自动处理的。相反动态对象的分配与释放必须由程序员显式地管理。
内存泄露(memory leak)是指一块动态分配的内存,我们不再拥有指向这块内存 的指针,因此我们没有办法将它返还给程序供以后重新使用。
第3章 C++数据类型
1. 常用的转义字符
| backspace(退格键) \b | carriage return (回车键) \r | alert (beel) (响铃符) \a | single quote (单引号) \' |
| horizontal tab(水平制表键) \t | newline(换行符) \n | backslash (反斜杠键) \\ | double quote (双引号) \" |
| vertical tab(垂直制表键) \v | formfeed (进纸键) \f | question mark (问号) \? |
|
2. 变量
什么是变量?变量是程序的静态存储区域中的一块内存区域的名字。
变量和文字常量都有存储区域,并且也有相关的类型。区别在于变量是可寻址的。
对于每一个变量,都有两个值与其关联:
(1)它的数值(右值,只能读取)(2)它的地址(左值,可以被赋值)
3. 关键字
c89中有32个关键字,C99添加5个
| auto 1 | else enum extern 3 | register return 2 | void volatile 2 |
| break 1 | float for 2 | short signed sizeof static struct switch 6 | while 1 |
| case char const continue 4 | goto 1 | typedef 1 | inline restrict _Bool _Complex _Imaginary 5 |
| default do double 3 | if int long 3 | union unsigned 2 |
|
| asm auto 2 | false float for friend 4 | namespace new 2 | template this throw ture try typedef typeid typename 8 |
| bool break 2 | goto 1 | operator 1 | union unsigned using 3 |
| case catch char class const const_cast continue 7 | if inline int 3 | private protected public 3 | virtual void volatile 3 |
| default delete do double dynamice_cast 5 | long 1 | register reinterpret_cast return 3 | wchar_t while 2 |
| else enum explicit export extern 5 | mutable 1 | short signed sizeof static static_cast struct switch 7 | 操作符替代名(11): |
4. const限定符
一般编译器不能跟踪指针在程序中任意一点指向的对象。(这种内部工作需要根据数据流分析(data flow analysis),通常由单独的优化器(optimizer)组件来完成)
5. 枚举类型
enum MODE{IN,OUT,APPEND}
我们不能使用枚举成员进行迭代:
//wrong
for ( open_modes iter = input; iter != append; ++iter )
// ...
C++不支持在枚举成员之间前后移动
我们可以定义枚举类型的对象,并且我们只能够使用相同枚举类型的对象或枚举成员来进行初始化。
但是,在必要时,枚举类型会自动被提升为算术类型。
如:
const int array_size = 1024;
// ok: pt2w 被提升成 int 类型
int chunk_size = array_size * pt2w;
第4章 表达式
1. 算术异常
算术异常主要归咎于算术的自然本质(比如除以0)或归咎于计算机的自然本质(比如溢出)
第7章
1. 缺省实参
函数调用的实参按位置解析,缺省实参只能用来替换函数调用缺少的尾部实参。
函数声明可以为全部或部分参数指定缺省实参。在左边参数的任何缺省实参被提供之前,最右边未初始化参数必须被提供缺省实参。这是由于函数调用的实参是按照位置解析的。
一个参数只能在一个文件中被指定一次缺省实参。
习惯上,缺省实参在公共头文件包含的函数声明中指定,而不是在函数定义中。如果缺省实参在函数定义的参数表中提供,则缺省实参只能用在包含该函数定义的文本文件的函数调用中。
函数后继的声明中可以指定其他缺省实参——一种对特定应用定制通用函数的有用方法。
【1】
2. 返回值
C++中,如果函数返回一个左值,那么对返回值的任何修改都将改变被返回的实际对象。
为了防止对返回值的无意修改,返回值应该被声明为const:
const int &get_val(...)
3. 函数指针
当一个函数名没有被调用操作符修饰时,会被解释成指向该类型函数的指针。
将取地址操作符作用在函数名上也能产生指向该函数类型的指针。
利用函数指针调用函数时,不需要解引用操作符。无论是用函数名直接调用函数,还是用指针间接调用函数,两者的写法都是一致的。
4. 指向extern “C“函数的指针
指向C函数的指针与指向C++函数的指针类型不同。所以如果用指向C++函数指针去为指向C函数的指针来进行赋值或初始化的话会产生编译错误。
如:
extern "C" void (*pf1)(int);
void(*pf2)(int);
pf1=pf2;//error
当链接指示符应用在一个声明上的时候,所有被它声明的函数都将受到链接指示符的影响。
如:
// pfParm 是一个指向 C 函数的指针
extern "C" void f1( void(*pfParm)(int) );
第8章 域和生命期
1.类型安全机制(type-safe-linkage)
在c++中,有一种机制,通过它可以把函数参数的类型和数目编码在函数名中,叫做类型安全链接(type-safe linkage)。类型安全链接可以用来帮助捕捉不同文件中函数声明不匹配的情况。
不同文件中出现的同一对象或函数声明的其他类型不匹配情况,在编译或链接时可能不会被捕捉到.因为编译器一次只能处理一个文件,它不能很容易地检查到文件之间的类型违
例.这些类型违例可能是程序严重错误的根源.例如, 文件之间错误的对象声明或函数返问类型就不能被检测出来.这样的错误只能在运行时刻异常或程序的错误输出中才能被揭示出
来.
2. 常量折叠(constant folding)
常量折叠(Constant folding)是其中一种被很多现代编译器使用的编译器最优化技术。常量折叠是在编译时间简单化常量表达的一个过程。简单来说就是将常量表达式计算求值,并用求得的值来替换表达式,放入常量表。可以算作一种编译优化。
例如
const int i=100;
const int j=i+10;
在编译时并没有给i和j 分配存储空间,也就是说遇到i就用100代替,编译同时也进行了简单的常量计算,所以遇见j就用110代替,这样i和j就不占用内存了。若是要做取地址操作,比如:long address =(long)&j; 这就需要为常量j分配内存空间了,但其值是不可改变的。
编译器会为常量分配了地址,但是在使用常量的时,常量会被一立即数替换(保护常量,防止被破坏性修改)
3. 动态内存分配
【2】
4. 定位new表达式
【3】