第一条 vector的使用
1.vector<T>::at和vector<T>::operator[]的区别
有两种途径访问vector内的元素,vector<T>::at或者vector<T>::operator[],vector<T>::at强制对下标进行检查,vector<T>::operator[]可以,但不强制对下标进行检查.
2.size/resize和capacity/reserve之间的区别
size告诉你容器中目前实际有多少个元素,而对应地,resize则会在容器的尾部添加或删除一些元素,来调整容易当中实际的内容,使容器达到指定大小.这两个函数对list,vector,deque都使用,但对其它容器并不使用.
capacity则告诉你最少添加多少个元素才会导致容器重新分配,而reserve在必要的时候总是会使容器的内部缓冲区扩充至一个更大的容量,以确保至少能满足你所指出的空间大小.这两个函数仅对vector使用.
3.一些准则
确保const正确性.特别是不对容器内的元素做任何改动的时候,记得使用const_iterator.
尽量使用!=而不是<来比较两个迭代器.
养成默认情况下使用前缀形式的--和++的习惯,除非你的确需要用到原来的值.
实施复用:尽量复用已有的算法,特别是标准库算法,而不是手写循环.
第二条 字符串格式化的"动物庄园"之一:sprintf
1.效率是以牺牲内存管理封装性而换取的.
2.主模板的应用
template<typename T>
void PrettyFormat(T value, char *buf); //注意:主模板只有声明,没有定义
template<> void PrettyFormat<int>(int value, char *buf){
sprintf(buf, "%d", value);
}
template<> void PrettyFormat<char>(char value, char *buf){
sprintf(buf, "%c", value);
}
//......还有其他特化版本......
第三条 字符串格式化的"动物庄园"之二:标准的(或极度优雅的)替代方案
一.c/c++字符串格式化方案
sprintf snprintf stringstream strstream boost::lexical_cast
是 是 否 否 是
是 是 否 是 否
否 是 是 是 是
否 否 是 是 是
否 否 是 是 是
从上表可以看出snprintf是sprintf的一个更好替代,stringstream是strstream的一个更好替代.如果注重代码简洁和效率,选择snprintf;如果注重安全性,选择stringstream.
第四条 标准成员函数
第五条 泛型性的风味之一:基础
第六条 泛型性的风味之二:够"泛"了吗
第七条 为什么不特化函数模板
第八条 友元模板
在代码中明确表达出你的意图.如果你所指的的确是一个模板,然而你的表达方式可能存在歧义的话,可以在模板名字的后面加上模板实参列表(这个列表可能是空的,即<>).
避开语言的冷僻特性,包括那些虽然可以说是合法但容易使程序员甚至编译器迷惑的地方.
当你想将来一个函数模板声明为友元的时候,一定要显示地加上一个模板列表(<...>),那怕是空的模板列表<>也行,因为它至少能够明确表示你所指的是一个模板.
namespace boost{
template<tempname T> void checked_delete(T *x);
}
class Test{
friend void boost::checked_delete(Test *x); //糟糕的做法
friend void boost::checked_delete<>(Test *x); //好的做法
}
然而,如果你的编译器目前连这两种合法的语法都不允许的话,你就只能将某些函数放到公用区段了.
第九条 导出限制之一:基础
1.包含式和分离式
包含式和分离式只是指代码组织方式的不同,并没有其他实质的差别.
包含式是指模板的声明和实现都在h文件中.
分离式是指模板的声明在h文件中,实现在cpp文件中.
2.export用法
//file g.h 给用户使用的
namespace MyLib{
export template<typename T>
void g(T&);
}
//file g.cpp
namespace MyLib{
template<typename T>
void g(T&){
//优雅而炫目的实现
//使用了一些其他类或模板,现在被"分离式"编译了
}
}
第十条 导出限制之二:相互影响,可用性问题以及准则