TAG / c++

do...while(0) 的妙用

在 C++ 中,有三种类型的循环语句:for、while 和 do...while,但是在一般应用中作循环时,我们可能用 for 和 while 要多一些,do...while 相对不受重视。
但是,最近在读我们项目的代码时,却发现了 do...while 的一些十分聪明的用法,不是用来做循环,而是用作其他来提高代码的健壮性。

CONTINUE READING »


让 C++ 的 new 操作失败时返回空指针

C 中如果创建一个对象失败,就会返回空指针。但是对于 C++ 就不一样了,new 是不应返回空指针的,书上的推荐做法是在构造函数里抛异常。
当不想引入异常机制的时候,一般的做法是在构造器里啥都不做(最多做个变量初始化),加一个 Init() 函数来完成真正的初始化工作。
然而这样就使得每次创建一个对象,都要执行两步(new+init),总不是太方便,其实 C++ 的 new 操作符是带参的,可以通过“new(std::nothrow) CXxx”的方式让 new 失败时返回 null 指针,来标记失败(而不是抛出异常)。


严重避免在构造/析构过程中调用虚函数

之前只知道在 C++ 的构造器中,调用虚函数(非纯虚函数)不会出现多态的情况,却想当然认为既然析构器可以被声明为虚“函数”,那么析构器应该是能实现虚函数调用的的多态结果的。
事实证明,我又被蒙骗了!

构造器/析构器不会在调用虚函数时执行子类的重载实现,而且更危险的是当构造器/析构器“间接地”调用了虚函数(例如调用了一个非虚函数,但这个函数里调用了虚函数),不仅子类的重载实现不会被执行,而且还很难发现这种 bug。

所以,切记,切忌在构造器/析构器中直接或间接地调用任何虚函数!(单是在构造器/析构器中直接或间接地调用其他对象的虚函数并不受影响)


#ifdef 中的逻辑与或操作

原本用宏定义包起来的代码类似如下:

#ifndef A
// codes
#endif // A

现在要加入一个宏定义 B,实现类似这样的条件判断(显然实际上这样是不行的):

#ifndef A && ifdef B

其实应该这样:

#if (!defined A) && (defined B)
// codes
#endif // !A && B

这就修正了之前一直以为的“既生 #ifdef,何生 #if defined”的思维,其实还是有差别的


用 前置声明,还是用 #include?

为了能让编译速度快一点,明智之举是使用前置声明,而不是 #include 整个头文件。

那声明时候可以用前置声明,而什么时候必须 #include 头文件呢?简单的说:

  1. 当不需要用到类型的具体实现时,包括构造器赋值运算符成员函数等,只需要前置声明就可以了
  2. 当需要用到类型的以上方法时,就不得不 #include 整个头文件

对该技巧的具体分析可以参考这里这里


(const int * i || int const * i) && int * const i

记了无数遍,终于记清楚了。。

const int * i 和 int const * i:

const 修饰后面的 * i,即 i 所指向的 int 空间内的数值不能被改变,但i的指向可以被改变,例如操作

int j = 1;
const int * i = &j;
*i = 2;

是非法的,但是

int j = 1, k = 2;
int * const i = &j;
i = &k;

是合法的;

int * const i:

cons 修饰后面的 i,即 i 的指向不能被改变,但 i 所指向的 int 空间内的数值可以被改变,和上面的例子正好相反。


« Newer Posts