Effective C++ 学习一

从c语言世界来到C++世界~~

Item1 优先使用const 和inline来取代#define

这个准则应该理解成优先依靠compiler而不是依靠preprocessor来检查程序的错误。

定义一个常量的格式 const int NUM_LIMIT = 100;

1  当定义常量指针的时候,事情略微变得复杂

    const char * pConst const = "is a constant pointer points to const";

2 定义一个类的常量成员变得简单。

class GamePlayer{

private :

    static const int NUM_TURNS = 5;//注意这里的NUM_TURNS仅是个变量的声明

    int scores[NUM_TURNS];

};

在函数的实现部分加入NUM_TURNS 的定义,这是必须,否则linker在link stage会提示出错。

const int GamePlayer::NUM_TURNS;

3 在你需要在class A编译阶段使用class A constant时候

class GamePlayer {

private:

        enum {NUM_TURNS = 5};

        int scores[NUM_TURNS];

......

}

#define max(a, b) ((a) > (b) ? (a) : (b))

宏定义一些简单常用函数,可以减少调用函数的开销, 它同时has many drawbacks,

int a = 5, b = 10;

max(++a, b);

max(++a, b+10);

看看会有什么奇怪的事情发生

用inline来代替macro define定义。

inline int max(int a, int b) { return a > b ? a : b; }

更近一步使用,使用Generic programming:

template<class T>

inline const T& max(const T& a, const T& b) {return a > b ? a : b;}

Item 2 优先使用iostream 而不是stdio.h。

1 iostream提供了更好的扩展性和类型安全的。

<iostream>和<iostream.h>

iostream是将std命名空间的成员引入程序,而iostream.h将global namespace中的成员引入,这样可能会导致namespace 污染。

Item 7 准备好内存溢出情况发生后如何处理

当使用new操作符分配堆内存的时候, 如果可用内村用光, 则会抛出bad_alloc 异常。 bad_alloc异常是有operator new导致的异常,他在内存请求不能被满足的时候(内存用光)被抛出。

按照c风格,你可能定义一个宏来处理out of memory异常,如

#define NEW (PTR, TYPE) try {PTR=new TYPE;} catch (std::bad_alloc&) {assert(0);}

ps: 其中assert是一个宏其对应的h文件为c <assert.h>和c++ <cassert> 该宏检查传递给它的表达式是否是非零, 如果是零,则返回一个出错信息并且调用abort中止程序执行。

但是这样就够了吗? 答案是不够。因为它忽略了new的多种分配内存空间的方法, 可以想到的是

new TYPE; new TYPE(construction parameters); new TYPE[buffer_length]

还有更加复杂的情况, 因为在C++中,用户可以自己定义其operator new的行为,这样算来, 可能的情况何止区区3,4种。所以这种方式不能满足我们的需求。

那应该怎么做呢?

答案是通过定义自己的out of memory handler函数来处理out of memory异常。调用set_new_handler【在<new>头文件中定义】

set_new_handler的声明大概是这个样子:

typedef void (*new_handler)();

new_handler set_new_handler(new_handler p) throw();

set_new_handler的使用方式如下:

定义你自己的handler函数, 然后装载到Global namespace当中去。

void noMoreMemory() {

    cerr<< "Unable to satisfy the memory request.";

    abort();

}

int main()

{

    set_new_handler(noMoreMemory);

    int * p = new int[10000000];

}

这样当请求内存不能被满足的时候, 首先打印出错误信息, 然后才会abort 程序。这样就比简单的core dump(清空寄存器,信息转存)要好的多。

可以装载新的handler就一样可以卸载handler, 具体:

set_new_handler(null);

当operator new不能分配足够的内存时, 它会重复执行调用handler function,直到内存请求可以被满足为止.

所以设计良好的handler函数应该可以完成以下动作中的一种:

1 分配更多内存或会使分配的内存以满足内存请求

2 安装不同的handler函数来处理该请求。 如果当前的handler函数不能处理当前的请求,但是它知道其它的handler函数可以处理这个请求, 所以它会装载另外一个handler函数。这样,在下次该请求不能被满足的时候,

新安装的handler function就会被调用来处理该请求。

3 卸载handler函数, set_new_handler(null),这样在处理out of memory时将抛出异常bad_alloc.

4 Throw exception: 如果自定义exception,需要继承bad_alloc,使其形成类层次结构。

5 not return: 默认行为是abort 或 exit.

对应于类来说:

class X {

public :

    static new_handler set_new_handler(new_handler p);

    static void * operator new (size_t size);

private:

    static new_handler currentHandler;

}

new_handler X::currentHandler;

new_handler X::set_new_handler(new_handler p){

    new_handler oldHandler = currentHandler;

    currentHandler = p;

    return oldHandler;

}

而对于X的operator new 的动作:

1 调用global的set_new_handler,来加载X的currentHandler

2 调用global的new操作, ::new 来进行内存分配。 如果内存分配不能满足,global new operator将会调用X的handler, 也就是刚被装载成为global 的handler, 如果new最终都不能满足内存分配请求, 它将抛出bad_alloc异常, 会被捕获, 同时会重新装载原来的global new-handler.并且重新抛出异常

3 如果分配请求成功 X的operator new会重新装载原来的global new handler.

在考虑一下, X的out of memory处理和X本身无关, 可以使用继承和template来生成可以重用的代码。

template <class T>

class NewHandlerSupport {

public:

    static new_handler set_new_handler (new_handler p);

    static void* operator new (size_t size);

private :

    static new_handler currentHandler;

}

template <class T>

new_handler NewHandlerSupport<T>::set_new_handler(new_handler p)

{

    new_handler oldHandler = currentHandler;

    currentHandler = p;

    return currentHandler;

}

template<class T>

void * NewHandlerSupport<T>::operator new (size_t t )

{

    new_handler globalHandler = std::set_new_handler(currentHandler);

    void * memory;

    try {

    memory = ::operator new (t);

} catch (bad_alloc&) {

    std::set_new_handler(globalHandler);

    throw;

}

    std::set_new_handler(globalHandler);

    return memory;

}

为Class X添加自己的set_new_handler就变成

class X: public NewHandlerSupport<X> {

    ....

}

对于new operator, 直到1993 ,对应于new 的out of memory, new在调用handler函数后 返回空指针(0)而不是抛出异常。支持这张形式的定义是Widget* wp = new (nothrow) Widget();

posted @ 2011-07-18 18:45  yub0yue  阅读(281)  评论(0编辑  收藏  举报