您的位置:首页 > 编程语言 > C语言/C++

C++中的内存管理——对effective c++第二章的总结

2007-07-17 17:22 429 查看
operator new在无法完成内存分配请求时会抛出异常(以前的做法一般是返回0),也可以当内存分配请求不能满足时,调用你预先指定的一个出错处理函数。即当operator new不能满足请求时,会在抛出异常之前调用客户指定的该出错处理函数——一般称为new-handler函数。指定出错处理函数时要用到set_new_handler函数,set_new_handler的输入参数是operator new分配内存失败时要调用的出错处理函数的指针,返回值是set_new_handler没调用之前就已经在起作用的旧的出错处理函数的指针。它在头文件<new>里大致是象下面这样定义的:
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();

可以象下面这么使用set_new_handler函数:

// function to call if operator new can't allocate enough memory
void nomorememory()
{
cerr << "unable to satisfy request for memory/n";
abort();
}

int main()
{
set_new_handler(nomorememory);
int *pbigdataarray = new int[100000000];

...

}

注意operator new内部包含一个无限循环,实际上会不只一次地尝试着去分配内存,它要在每次失败后调用出
错处理函数。所以一个设计得好的new-handler函数必须实现下面功能中的一种。
·产生更多的可用内存。这将使operator new下一次分配内存的尝试有可能获得成功。实施这一策略的一
个方法是:在程序启动时分配一个大的内存块,然后在第一次调用new-handler时释放。释放时伴随着一些对用
户的警告信息,如内存数量太少,下次请求可能会失败,除非又有更多的可用空间。

·安装另一个不同的new-handler函数。如果当前的new-handler函数不能产生更多的可用内存,可能它会
知道另一个new-handler函数可以提供更多的资源。这样的话,当前的new-handler可以安装另一个new-handler
来取代它(通过调用set_new_handler)。下一次operator new调用new-handler时,会使用最近安装的那个。(这
一策略的另一个变通办法是让new-handler可以改变它自己的运行行为,那么下次调用时,它将做不同的事。方
法是使new-handler可以修改那些影响它自身行为的静态或全局数据。)

·卸除new-handler。也就是传递空指针给set_new_handler。没有安装new-handler,operator new分配内
存不成功时就会抛出一个标准的std::bad_alloc类型的异常。

·抛出std::bad_alloc或从std::bad_alloc继承的其他类型的异常。这样的异常不会被operator new捕捉,
所以它们会被送到最初进行内存请求的地方。(抛出别的不同类型的异常会违反operator new异常规范。规范中
的缺省行为是调用abort,所以new-handler要抛出一个异常时,一定要确信它是从std::bad_alloc继承来的。

·没有返回。典型做法是调用abort或exit。abort/exit可以在标准c库中找到。

c++不支持专门针对于类的new-handler函数,而且也不需要。你可以自己来实现它,只要在每个类中提供自己版
本的set_new_handler和operator new。类的set_new_handler可以为类指定new-handler(就象标准的
set_new_handler指定全局new-handler一样)。类的operator new则保证为类的对象分配内存时用类的new-handler
取代全局new-handler。因为operator new对类类型的对象分配内存失败时,每次都必须调用出错处理函数,所以
要在类里声明一个new_handler类型的静态成员。

之所以有时需要定义自己的operator new和operator delete?最主要的原因是为了效率。缺省版本的operator new是一种通用型的内存分配器,它必须可以分配任意大小的内存块。同样,operator delete也要可以释放任意大小的内存块。operator delete想弄清它要释放的内存有多大,就必须知道当初operator new分配的内存有多大。所以在new所返回的内存里预先附带一些额外信息,用来指明被分配的内存块的大小。如果软件运行在一个内存很宝贵的环境中,且需要分配多个很小的类对象,就承受不起这种奢侈的内存分配方案了。 具体的实现是先让缺省operator new分配一些大块的原始内存,每块的大小都足以容纳很多个小的类对象。该类对象的内存块就取自这些大的内存块。当前没被使用的内存块被组织成链表(称为自由链表)以备将来该类对象使用。在实际开发中,还可以把这种固定大小内存的分配器封装起来,从而可以更加方便地使用(参考effective c++条款10)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: