C 箴言:理解 new-handler的行为

2008-02-23 05:05:50来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

 当 operator new 不能满足一个内存分配请求时,他抛出一个 exception(异常)。很久以前,他返回一个 null pointer(空指针),而一些比较老的编译器还在这样做。您依然能达到以前的目的(在一定程度上),但是我要到本文的最后再讨论他。

  在 operator new 因回应一个无法满足的内存请求而抛出一个 exception 之前,他先调用一个能够由客户指定的被称为 new-handler 的 error-handling function(错误处理函数)。(这并不完全确切,operator new 真正做的事情比这个稍微复杂一些,周详细节将在下一篇文章中讨论。)为了指定 out-of-memory-handling function,客户调用 set_new_handler ——一个在 <new> 中声明的标准库函数:

namespace std {
 typedef void (*new_handler)();
 new_handler set_new_handler(new_handler p) throw();
}

  就像您能够看到的,new_handler 是个指针的 typedef,这个指针指向不取得和返回任何东西的函数,而 set_new_handler 是个取得和返回一个 new_handler 的函数。(set_new_handler 的声明的结尾处的 "throw()" 是个 exception specification(异常规范)。他基本上是说这个函数不会抛出任何异常,尽管真相更有趣一些。关于细节,参见《C 箴言:争取异常安全的代码》。)

  set_new_handler 的形参是个指向函数的指针,这个函数是 operator new 无法分配被请求的内存时应该调用的。set_new_handler 的返回值是个指向函数的指针,这个函数是 set_new_handler 被调用前有效的目标。

  您能够像这样使用 set_new_handler:

// function to call if operator new can't allocate enough memory
void outOfMem()
{
 std::cerr << "Unable to satisfy request for memory\n";
 std::abort();
}
int main()
{
 std::set_new_handler(outOfMem);
 int *pBigDataArray = new int[100000000L];
 ...
}

  假如 operator new 不能为 100,000,000 个整数分配空间,outOfMem 将被调用,而程式将在发出一个错误信息后中止。(顺便说一句,考虑假如在写这个错误信息到 cerr... 的过程中内存必须被动态分配会发生什么。)

  当 operator new 不能满足一个内存请求时,他反复调用 new-handler function 直到他能找到足够的内存。但是从这种高层次的描述已足够推导出一个设计得好的 new-handler function 必须做到以下事情之一:

  ·Make more memory available(使得更多的内存可用)。这可能使得 operator new 中下一次内存分配的尝试成功。实现这一策略的一个方法是在程式启动时分配一大块内存,然后在 new-handler 第一次被调用时释放他供程式使用。

  ·Install a different new-handler(安装一个不同的 new-handler)。假如当前的 new-handler 不能做到使更多的内存可用,或许他知道有一个不同的 new-handler 能够做到。假如是这样,当前的 new-handler 能在他自己的位置上安装另一个 new-handler(通过调用 set_new_handler)。operator new 下一次调用 new-handler function 时,他会得到最近安装的那一个。(这个主线上的一个变化是让一个 new-handler 改变他自己的行为,这样,下一次他被调用时,能够做一些不同的事情。做到这一点的一个方法是让 new-handler 改变能影响 new-handler 行为的 static(静态),namespace-specific(名字空间专用)或 global(全局)的数据。)

  ·Deinstall the new-handler(卸载 new-handler),也就是,将空指针传给 set_new_handler。没有 new-handler 被安装,当内存分配没有成功时,operator new 抛出一个异常。

  ·Throw an exception(抛出一个异常),类型为 bad_alloc 或继承自 bad_alloc 的其他类型。这样的异常不会被 operator new 捕获,所以他们将被传播到发出内存请求的地方。

  ·Not return(不再返回),典型情况下,调用 abort 或 exit。

  这些选择使您在实现 new-handler functions 时拥有极大的弹性。

  有时您可能希望根据被分配 object 的不同,用不同的方法处理内存分配的失败:

class X {
public:
 static void outOfMemory();
 ...
};
class Y {
public:
 static void outOfMemory();
 ...
};
X* p1 = new X; // if allocation is unsuccessful,
// call X::outOfMemory

Y* p2 = new Y; // if allocation is unsuccessful,
// call Y::outOfMemory

  C 没有对 class-specific new-handlers 的支持,但是他也无需。您能够自己实现这一行为。您只要让每一个 class 提供 set_new_handler 和 operator new 的他自己的版本即可。class 的 set_new_handler 允许客户为这个 class 指定 new-handler(正像standard set_new_handler 允许客户指定global new-handler)。class 的 operator new 确保当为 class objects 分配内存时,class-specific new-handler 代替 global new-handler 被使用。

  假设您要为 Widget class 处理内存分配失败。您就必须清楚当 operator new 不能为一个 Widget object 分配足够的内存时所调用的函数,所以您需要声明一个 new_handler 类型的 static member(静态成员)指向这个 class 的 new-handler function。Widget 看起来就像这样:

class Widget {
public:
 static std::new_handler set_new_handler(std::new_handler p) throw();
 static void * operator new(std::size_t size) throw(std::bad_alloc);
private:
 static std::new_handler currentHandler;
};

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: 再谈C语言中数组和指针之间的互操作

下一篇: VC 实现应用程式对插件的支持