1. 不能在容器中使用auto_ptr,要用boost的share_ptr。具体原因可以查auto_ptr的特性。
2. 别用vector<bool>。
3. 如果将派生类直接赋值给基类,派生类独有的信息将丢失。因此这种情况,最好用指针,将派生类的指针赋值给基类的指针变量。
4. 生成std::map的时候,键值可以是任何类,只要这个类定义了比较大小的操作。
5. 赋值拷贝和构造赋值(copy constructor and assignment operator )如果没有定义,设置成private。
6. 如果派生类需要定义析构函数,请将基类的析构函数设成虚函数。
7. 避免在头文件中定义 "using namespace"
8. 在c++中总是用#include <cstdio>,不要用 #include <stdio.h> 。其他头文件类似。
9. 复杂的对象,不要通过按值传递的方式传递,尽量用const reference的方式传递。
10 不要把很大的数据放在stack中 , Must be <64kb
11. 避免使用non-const static 变量,如果要使用,也要设法加保护措施。
12 不要在assert 语句中进行表达式的计算。
13 编译链接时候的任何warnning信息,都应该清除。
14. 不要对multimap用[]操作符,它不支持。可以用map<int, vector<int>>代替multimap<int,int>。
15. 对STL的容器进行了erase或者insert以后,如果不能确定,要假定已经有的引用和指针还有迭代器失效。各个容器的效果不一样。可以查各个容器的介绍。
16.定义自己的类,请参考《c++沉思录》中的类设计者审查表。后面会附录一篇文章。
17. 以后补充
附录:
如何定义一个完整的类
定义一个类时必须搞清楚的几个问题:
需要构造函数吗?
如果答案为 no,那么很可能你需要定义的只是一个结构,而不是一个类,因为构造函数的用途是用一种明确定义的状态来设置对象。
数据成员是私有的吗?
一般来说,如果数据成员为公有,你很难控制这些成员何时被访问。
需要一个无参数的构造函数吗?
如果一个类已经有了构造函数,而你想声明该类的对象时不必显示地初始化它们,则必须显示地写一个无参数的构造函数。(特别是当你需要生成这个类的对象数组时!)
每个构造函数是否都对所有数据成员进行了初始化了?
对象的状态由对象的数据成员反映,因此每个构造函数都有负责为所有的数据成员设置经过明确定义的值。如果某个构造函数没有做到这一点,就很可能导致错误。(当然,这种说法未必总是正确的。因为有时,某些数据成员,只有在该对象存在了一定的时间后才有意义。)
需要析构函数吗?
并不是所有的类都需要析构函数的。一般来说,如果一个类分配了资源,并且这些资源不会被成员函数自动释放,那么这个类就需要一个析构函数。
需要一个虚析构函数吗?
任何不作为基类的类是不需要虚析构函数的,虚析构函数只有在继承的情况下才有用。当可能发生 delete 一个类型为基类的指针,可实际上该指针代表的是一个子类的对象,这个基类定义时需要一个虚析构函数。
需要一个复制构造函数吗
如果用类缺省的复制构造函数复制该类的对象时,如果能完整复制该类的数据成员和基类对象,就不需要复制构造函数,否则就需要。特别是,如果你的类在构造函数内分配了资源,或者在成员函数中分配了资源,则很可能需要一个显示的复制构造函数来管理资源。有析构函数(除了空的析构函数外)的类通常是用析构函数来释放资源,这通常也说明需要一个复制构造函数。
需要一个赋值操作符吗?
如果你的类需要复制构造函数,多半也需要一个赋值操作符。当然,如果你不想用户设置类中的对象,可以将赋值操作符声明为私有的。
赋值操作符能正确地将对象赋给对象本身吗?
自我赋值是常犯的错误!赋值总是用新值取代目标对象的旧值。如果原对象和目标对象是同一个,而我们又奉行“先释放旧值,再复制新值”的原则,那么就可能在还没有实施复制之前就把原对象销毁了!
需要定义关系操作符吗?
如果你的类需要放入 stl 的容器中,很可能需要定义关系操作符。把一个新对象加入容器中,某些容器,需要把新对象与容器里已有的对象进行比较,比如进行相等比较,进行大小比较。因此,如果类逻辑上支持相等操作,那么提供 operator== 和 operator!= 就会很有好处。类似,如果类的值有某种排序关系,你就可以提供 operator< 或者 operator> 等关系操作符。只要这些容器需要创建你的类的有序集合,你就必须提供关系操作符。
删除数组时记住用 delete[] 了吗?
在删除任何类型的数组时使用 delete[] 是一种很好的习惯。
在复制构造函数和赋值构造函数的参数类型中加上 const 了吗?
这是某些 C++ 著作中也会犯的错误!
如果函数有引用参数,只有在函数想改变函数的输入参数时,才应该不用 const 声明该引用参数!通常这个会被改变的输入参数也肩负着输出参数的角色。
记得适当地声明成员函数为 const 了吗?
如果确信一个成员函数不用修改它的对象,就可以声明它为 const。
一个需要上述所有特性类定义的例子
// 声明
class A{
public:
A();
virtual ~A();
A(const A& s);
A& operator=(const A& s);
bool operator==(const A& s) const;
bool operator!=(const A& s) const;
bool operator<(const A& s) const;
};
// 实现
A::A(){
// todo...
}
A::~A(){
// todo...
}
A::A(const A& s){
// todo...
}
A& A::operator=(const A& s){
if(&s != this){
// todo...
}
return *this;
}
bool A::operator==(const A& s) const{
// todo...
return false;
}
bool A::operator!=(const A& s) const{
return !((*this)==s);
}
bool A::operator<(const A& s) const{
// todo...
return false;
}