1. 前置声明delete : 仅仅前置生命一个类型,然后delete这个类型的指针,会回收内存,但却不会调用该类析构函数。
示例:
class A;
void DeleteWithoutDtor(A *pA)
{
delete pA;
}
2. for_each 与transform差异
for_each参数为输入迭代器(只读),transform则带有输出迭代其参数,可写。
对于for_each不可使用SAFE_DELETE_PTR等,因为该操作有写操作。应该使用transform.
3. const
const作为修饰词,其所修饰物为不可变。
如const char* p = "abc". const 修饰(*p),则(*p)即p 指向之物不可变。(但其本身可变)。
而char * const p = "abc". const 修饰(p).则(p)即p指针本身不可变。(但其指向植物可变)。
4. 赋值运算符与拷贝构造函数。
A a;
A a2(a); //拷贝构造函数
A a3 = a; //拷贝构造函数
a3 = a2; //赋值运算符。
5. typename
作为模板参数,其与class 几乎没区别,但在模板类作为模板参数时则不同,必须如下用法:template< template<typename T> class C>
作为类型标识 ,typename 往往用在模板类或模板函数受限类型前。
6. 接口类,虚析构函数
接口类必须定义虚析构函数,如果没有,子类析构函数调用不到,会引起各种隐藏bug. memsql的sdk头文件中居然都有这个问题,可想而知,大家是多么容易犯这个错。
7. 用c系string操作函数操作非'\0'结尾字符串。
会引起内存越界错误或数据错误,但很多时候不会崩溃,也是万恶bug的源泉。
8. std::vecotr用下标迭代远比用迭代器迭代效率高,由于下标访问等同访问原生数组指针,而迭代器访问则需要不断构造大量迭代其对象。
9. std::map, std::set 在自定义comparator的时候需要考虑相等的条件,大多数stl map set实现中是用!(a<b) && !(b<a) 来表达a==b的。
10. 在任何时候为系统增加一个静态成员变量或者全局变量的时候都要考虑其生命周期管理(如果系统有相关管理机制,最好使用这些机制)。它会导致两个问题:1. 如果系统进程没有完全退出,则可能导致野指针错误,比如我们最熟悉的android系统。
2. 如果这些变量数目过多,将会导致大量的内存碎片及冗余内存占用。