版本10和12间的区别 (跳过第2版)
于2008-11-17 15:00:07修订的的版本10
大小: 4802
编辑: virtuos
备注:
于2008-11-17 17:36:55修订的的版本12
大小: 5340
编辑: virtuos
备注:
删除的内容标记成这样。 加入的内容标记成这样。
行号 23: 行号 23:
}}}应该定义成{{{ }}}应该定义成{{{#!cplusplus
行号 25: 行号 25:
}}}并写在用到它的类中,而不是一个全局的常量。 }}}并写在用到它的类中,而不是一个全局的常量。比如{{{#!cplusplus
#define M_Valid_Controller(x) ((x)->port!=-1 || (x)->slot!=-1)
}}}可以定义成{{{#!cplusplus
inline bool M_Valid_Controller(const ControllerInfo *x) {
    return x->port != -1 || x->slot != -1;
}
}}}
行号 58: 行号 64:
}}}上述switch结构总计有170个case,代码长达5000行。同样可以用数组来改造它{{{#! }}}上述switch结构总计有170个case,代码长达5000行。同样可以用数组来改造它{{{#!cplusplus
行号 64: 行号 70:
 * 资源获取即初始化。定义对象的时候,就将其初始化。如果还不能初始化,就推出创建对象,到能初始化的时候再创建。释放资源后,对象中将不在包括资源,对象本身也没有存在的必要,也应该立即销毁。
行号 66: 行号 73:
 * 速度至关重要时,用查表代替计算,避免浮点数。比如{{{  * 速度至关重要时,用查表代替计算,避免浮点数。比如{{{#!cplusplus

some tips on writing c++ codes to avoid potential bugs:

  • 先写注释再写代码,规范化的注释。按照doxygen的标准给类、函数、变量写注释。比如,类似这样的注释一点用处都没有:

       1 //----------------------------------------------------------------------------
       2 // @ SimDoor::SimDoor()
       3 // ---------------------------------------------------------------------------
       4 // Constructor
       5 //----------------------------------------------------------------------------
       6 SimDoor::SimDoor( const RSString& name )
    

    再比如

    比较好的写法应该类似这样:

       1         /// \brief check the block is saved or not
       2         /// \author Chen Zhongke
       3         /// \param filename the filename of the block data file.
       4         /// \result return -1 if filename doesn't exist, otherwise return the index of the file in buffer.
       5         int SimulateIsSaved(RSString filename);
    
    对于函数的注释应该写在头文件的声明中,而不是定义中。
  • 避免重复代码,使用函数。
  • 避免使用预编译

       1 #define kMaxFriends             2
       2 
    

    应该定义成

       1 static const int kMaxFriends = 2;
    

    并写在用到它的类中,而不是一个全局的常量。比如

       1 #define M_Valid_Controller(x) ((x)->port!=-1 || (x)->slot!=-1)
       2 
    

    可以定义成

       1 inline bool M_Valid_Controller(const ControllerInfo *x) {
       2     return x->port != -1 || x->slot != -1;
       3 }
    
  • 避免switch,用数据来简化代码。比如

       1         switch (index)
       2         {
       3                 case 0: return RP_VALUE0;
       4                 case 1: return RP_VALUE1;
       5                 case 2: return RP_VALUE2;
       6                 case 3: return RP_VALUE3;
       7                 case 4: return RP_VALUE4;
       8                 case 5: return RP_VALUE5;
       9                 case 6: return RP_VALUE6;
      10                 case 7: return RP_VALUE7;
      11         }
    

    可以使用如下代码来代替

       1     int rp_values[] = {RP_VALUE0, RP_VALUE1, RP_VALUE2, RP_VALUE3, RP_VALUE4, RP_VALUE5, RP_VALUE6, RP_VALUE7};
       2     return rpvalues[index];
    

    再比如

       1         switch (statement)
       2         {
       3         case srTimerSet:
       4         {
       5                 //n lines of codes
       6 
       7                 break;
       8         }
       9         case srTimerKill:
      10         {
      11                 //n lines of codes
      12                 break;
      13         }
      14         // n cases
      15         return true;  
      16         }       
    

    上述switch结构总计有170个case,代码长达5000行。同样可以用数组来改造它

       1     bool (*response[])(void) = {TimerSetHandler, TimerKillHandler, ...};
       2     return responses[statement]();
    
    数组里面可以是函数,也可以是仿函数对象。
  • 注意代码统计质量,函数不可太长,方法不可太多,不可有太多子类,不可有太多父类。比如,IkeScriptMgr::CallResponse单个函数长达5000多行,一个类SimHuman有多达414个成员函数,IkeSceneContainer类的直接派生类(不包括间接继承的类)有100个,这些数字说明这些地方的设计很可能存在问题,需要考虑是否要重构。

  • 避免指针,避免数组,避免自己写常用的数据结构。可以使用stl,数组可以用vector代替,char[]用string代替,链表用list。指针指向的对象的地址不会变化,就用引用代替指针。
  • 资源获取即初始化。定义对象的时候,就将其初始化。如果还不能初始化,就推出创建对象,到能初始化的时候再创建。释放资源后,对象中将不在包括资源,对象本身也没有存在的必要,也应该立即销毁。
  • 避免用C++来实现OO design,注意对象的owner。在C++中,每个创建的对象都应该有明确的owner,owner负责该对象的创建和释放。当需要转移owner时,需要显式的调用对象的某个方法(比如Release),释放出对象的所有权。
  • 善用svn,大的修改应该建分支branch。避免一个人在自己的电脑上长时间做大幅的代码修改,等到完成了才与trunk合并。应该给这个人所做的修改创建一个分支,让他可以在这个分支上提交,等到这个分支的代码成熟了,将它与trunk合并。
  • 速度至关重要时,用查表代替计算,避免浮点数。比如

       1         float mScriptTime;
    
    这个变量表示时间,单位是秒,用float类型,参加运算的速度非常慢,而且容易出错(比如mScriptTime == 0.0f这个表达式容易因为精度问题一直为假。)可以使用整数,换作毫秒为单位就可以表示了。
  • 注意Singleton模式的实现。比如这样的实现

    class PlayerPanel{
    public:
            static PlayerPanel* Create() {
                    if(!mInstance)  mInstance = new PlayerPanel; 
                    return mInstance; 
            }
            static PlayerPanel* Get() { return mInstance; }
            static void Destroy() { delete mInstance; mInstance = NULL; }
    private:
            static PlayerPanel*                                     mInstance;      
    };

    需要注意的是,要保证只有一个对象存在,所有的构造函数都要写成私有。而且,虽然拷贝构造函数和赋值运算符没有用处,但是也要进行声明,并且声明成私有的(但是不需要进行定义)。

    private:
            PlayerPanel();
            ~PlayerPanel();
            PlayerPanel(const PlayerPanel&);
            PlayerPanel &operator=(const PlayerPanel&);

    还要注意的是,这样的实现对于多线程程序来说是不安全的,因为if(!mInstance)       mInstance = new PlayerPanel; 并不是一个原子的操作。

C++编程技巧 (2008-11-18 09:51:13由virtuos编辑)

ch3n2k.com | Copyright (c) 2004-2020 czk.