lint /splint
---------------------------------------------------------------------------------
左值表示存存储在计算机内存中的对象
NUL 结束一个ACSII字符串
NULL表示什么也不指向
---------------------------------------------------------------------------------
静态链接只装入需要的函数
cc main.c -lm 记住库放最后,最基础的放最后边,左边依赖右边
nm -sx a.out 查找符号表
size /dump
ldd
---------------------------------------------------------------------------------
检查源码工具
cb
indent
cdecl
cflow 打印程序中调用被调用者关系
cscope
ctags
lint
sccs 源码版本控制系统
vgrind 格式器
检查可执行文件的工具
dis 目标代码反汇编工具
dump -Lv 打印动态链接信息
ldd
nm
strings
sum
帮助调试工具
truss
ps
ctrace
debugger
file
性能优化工具
gprof
prof
tcov
time
---------------------------------------------------------------------------------
BSS "Block Started by Symbol" "Better Save Space" 不占目标文件空间 只保存没有值的变量
alloca() 分配的内存在stack
/usr/include/sys/frame.h 过程活动记录
<setjmp.h>
setjmp() longjmp() == c++ catch throm
---------------------------------------------------------------------------------
作为函数定义的形式参数 或 表达式中 数组=指针
没有办法把数组本身传给一个函数,因为它总是被自动转换为指向数组的指针。所以要给个长度
a[i] 编译器解释为 *(a+1)
---------------------------------------------------------------------------------
__FILE__ 文件名
__LINE__ 当前行号
__TIME__ 文件被编译的时间
__DATE__ 文件被编译的日期
<stdexcept>
<exception>
<type_info>
---------------------------------------------------------------------------------
具有 const 形 参或非 const 形参的函数并无区别
如果使用引用形参的唯一目的是避免复制实参,则应将形参定 义为 const 引用
编译器忽略为任何数组形参指定的长度
大部分情况下,数 组以普通的非引用类型传递,此时数组会悄悄地转换为指针。一般来说,非引用 类型的形参会初始化为其相应实参的副本。而在传递数组时,实参是指向数组第 一个元素的指针,形参复制的是这个指针的值,而不是数组元素本身。函数操纵 的是指针的副本,因此不会修改实参指针的值。然而,函数可通过该指针改变它 所指向的数组元素的值。通过指针形参做的任何改变都在修改数组元素本身
如果形参是数组的引用, 编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下, 数组大小成为形参和实参类型的一部分
C++ 程序,只能将简单数据类型传递给含有省略符形参的 函数。实际上,当需要传递给省略符形参时,大多数类类型对 象都不能正确地复制 省略符暂停了类型检查机制
内联函数应该在头文件中定义,这一点不同于其他函数
注意不能基于指针本身是否为 const 来实现函数的重载:
f(int *);
f(int *const); // redeclaration
int (*ff(int))(int*, int); 阅读函数指针声明的最佳方法是从声明的名字开始由里而 外理解。
要理解该声明的含义,首先观察: ff(int)
将 ff 声明为一个函数,它带有一个 int 型的形参。该函数返回 int (*)(int*, int);
---------------------------------------------------------------------------------
IO 对象不可复制或赋值
只有支持复制的元 素类型可以存储在 vector 或其他容器类型里。由于流对象不能复制,因此不能 存储在 vector(或其他)容器中
形参或返回类型也不能为流类型
对 IO 对象的读写会改变它的状态,因此引用必须是非 const 的
如果需要刷新所有输出,最好使用 unitbuf 操纵符
nounitbuf 操纵符将流恢复为使用正常的、由系统管理的缓冲区刷新方式
为了确保用户看到程序实际上处理的所有输出,最好的方法 是保证所有的输出操作都显式地调用了 flush 或 endl。
---------------------------------------------------------------------------------
在容器中添加元素时,系统是将元素值复制到容器里
s.find( args)在 s 中查找 args 的第一次出现
s.rfind( args)在 s 中查找 args 的最后一次出现
s.find_first_of( args)在 s 中查找 args 的任意字符的第一次出现
s.find_last_of( args)在 s 中查找 args 的任意字符的最后一次出现
s.find_first_not_of( args)在 s 中查找第一个不属于 args 的字符
s.find_last_not_of( args)在 s 中查找最后一个不属于 args 的字符
适配器(adaptor)是标准库中通用的概念,包括容 器适配器、迭代器适配器和函数适配器。本质上,适配器是使一事物的行为类似 于另一事物的行为的一种机制。容器适配器让一种已存在的容器类型采用另一种 不同的抽象类型的工作方式实现。例如,stack(栈)适配器可使任何一种顺序 容器以栈的方式工作
默认的 stack 和 queue 都基于 deque 容器实现,而 priority_queue 则 在 vector 容器上实现
stack 适配器 所关联的基础容器可以是任意一种顺序容器类型.
因此,stack 栈可以建立在 vector、list 或者 deque 容器之上。而 queue 适配器要求其关联的基础容器 必须提供 push_front 运算,因此只能建立在 list 容器上,而不能建立在 vector 容器上。priority_queue 适配器要求提供随机访问功能,因此可建立在 vector 或 deque 容器上,但不能建立在 list 容器上
map<K,V>::key_type 在 map 容器中,用做索引的键的类型
map<K,V>::mapped_type在 map 容器中,键所关联的值的类型
map<K,V>::value_type一个 pair 类型,它的 first 元素具有 const map<K, V>::key_type 类型,而 second 元素则为 map<K, V>::mapped_type 类型
对于 map 容器,如果下标所表示的键在容器中不存在,则添加新元素
m.count(k) 返回 m 中 k 的出现次数
m.find(k) 如果 m 容器中存在按 k 索引的元素,则返回指向该元素的迭代
set 存储的元素仅仅 是键,而没有所关联的值
set 容器只是单纯的键的集合
正如不能修改 map 中元素的键部分一样,set 中的键也为 const
m.lower_bound(k)返回一个迭代器,指向键不小于 k 的第一个元素
m.upper_bound(k)返回一个迭代器,指向键大于 k 的第一个元素
m.equal_range(k)返回一个迭代器的 pair 对象它的 first 成员等价于 m.
---------------------------------------------------------------------------------
算法永不执行容器提供的操作
使用“普通”的迭代器时,算法从不修
改基础容器的大小。正如我们所看到的,算法也许会改变存储在容器中
的元素的值,也许会在容器内移动元素,但是,算法从不直接添加或删
除元素
find_first_of,带有两对迭代器参数。每对迭代器中, 两个实参的类型必须精确匹配,但不要求两对之间的类型匹配。特别是, 元素可存储在不同类型序列中,只要这两序列的元素可以比较即可
vector<int> vec; // empty vector
// ok: back_inserter creates an insert iterator that adds elements to vec
fill_n (back_inserter(vec), 10, 0); // appends 10 elements to vec
back_inserter 函数是迭代器适配器
back_inserter 生 成一个绑定在该容器上的插入迭代器。在试图通过这个迭代器给元素赋值时,赋 值运算将调用 push_back 在容器中添加一个具有指定值的元素
back_inserter,创建使用 push_back 实现插入的迭代器。
• front_inserter,使用 push_front 实现插入。
• inserter,使用 insert 实现插入操作。除了所关联的容器外,inserter
还带有第二实参:指向插入起始位置的迭代器
istream_iterator 用于读取输入流,而 ostream_iterator 则用 于写输出流
尽管 map 和 set 类型提供双向迭代器,但关联容器只能使用算法的一 个子集。问题在于:关联容器的键是 const 对象。因此,关联容器不能 使用任何写序列元素的算法。只能使用与关联容器绑在一起的迭代器来 提供用于读操作的实参。
在处理算法时,最好将关联容器上的迭代器视为支
持自减运算的输入迭代器,而不是完整的双向迭代
器。
---------------------------------------------------------------------------------
普通的非 const 成员函数中,this 的类型是一个指向类类型的 const 指针,可以改变 this 所指向的值,但不能改变 this 所保存 的地址
在 const 成员函数中,this 的类型是一个指向 const 类类型对象的 const 指针。既不能改变 this 所指向的对象,也不能改变 this 所保存的地址
不能从 const 成员函数返回指向类对象的普通引用。const 成 员函数只能返回 *this 作为一个 const 引用
要将数据成员声明为可变的,必须将关键字 mutable 放在成员声明之前
形参表和函数体处于类作用域中
函数返回类型不一定在类作用域中
只要创建该类型的一个对象,编译器就运行一个构造函数
构造函数的工作是初始化对象。不管对象是 否为 const,都用一个构造函数来初始化化该对象
抑制由构造函数定义的隐式转换
可以通过将构造函数声明为 explicit,来防止在需要隐式转换的上下文中 使用构造函数
explicit 定义上不再重复它 关键字只能用于类内部的构造函数声明上
---------------------------------------------------------------------------------
复制构造函数、赋值操作符和析构函数总称为复制控制。编译器自动实现这 些操作,但类也可以定义自己的版本
有一种特别常见的情况需要类定义自己的 复制控制成员的:类具有指针成员
直接初始化 直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始 化首先使用指定构造函数创建一个临时对象,然后用复制构造 函数将那个临时对象复制到正在创建的对象
声明而不定义成员函数是合法的,但是,使用未定义成员的任何尝试将导致 链接失败。通过声明(但不定义)private 复制构造函数,可以禁止任何复制类 类型对象的尝试:用户代码中复制尝试将在编译时标记为错误,而成员函数和友 元中的复制尝试将在链接时导致错误
如果定义了复制构造函数,也必须定义默认构造函 数
如果类需要析构函数,则它也需要赋值操作符和复制构造函 数,这是一个有用的经验法则。这个规则常称为三法则,指 的是如果需要析构函数,则需要所有这三个复制控制成员
---------------------------------------------------------------------------------
以下4个操作符不能重载
:: .*.?:
重载操作符必须具有一个类类型操作数
优先级和结合性是固定的
不再具备短路求值特性
类通常将 IO 操作符设为友元
赋值必须返回对 *this 的引用
plus<Type>
minus<Type>
multiplies<Type>
divides<Type>
modulus<Type>
negate<Type>
equal_to<Type>
not_equal_to<Type>
greater<Type>
greater_equal<Type>
less<Type>
less_equal<Type>
logical_and<Type>
logical_or<Type>
logical_not<Type>
bind1st 将给定值绑定到二元函数对
象的第一个实参,bind2nd 将给定值绑定到二元函数对象的第二个实参
count_if(vec.begin(), vec.end(),
bind2nd(less_equal<int>(), 10));
count_if(vec.begin(), vec.end(),
not1(bind2nd(less_equal<int>(), 10)));
auto_ptr 对象只能保存一个指向对象的指针,并且不能用于指向动态分配 的数组
====================
char* sql=“xxx” “ff”;