3

在阅读这个问题之前,我从未认真对待异常处理。现在我看到了必要性,但仍然觉得“编写异常安全代码非常困难”。

请参阅该问题接受的答案中的此示例:

void doSomething(T & t)
{
   if(std::numeric_limits<int>::max() > t.integer)  // 1.   nothrow/nofail
      t.integer += 1 ;                              // 1'.  nothrow/nofail
   X * x = new X() ;                // 2. basic : can throw with new and X constructor
   t.list.push_back(x) ;            // 3. strong : can throw
   x->doSomethingThatCanThrow() ;   // 4. basic : can throw
}

正如答案所说,我可以通过使用轻松提供基本保证std::unique_ptr。但是,当我捕获 a 时std::bad_alloc,我不知道它是否发生在push_backorx->doSomethingThatCanThrow()中,所以我不知道 t.list 是否仍然“好”或者它的最后一个元素没有完全准备好。然后唯一的选择是丢弃 t,显示一个可怕的消息并中止,如果 t 对整个程序是必不可少的。

具有强保证的代码没有问题,但是“它可能会变得昂贵”(这个例子涉及到大列表的副本),并且不那么可读。

一个可能的解决方案可能是new等待内存可用,从而消除最烦人的异常std::bad_alloc。然后 2. 和 3. 不会抛出(前提X是构造和复制总是成功)。我可以将 4. 包装在一个 try 块中并在此处处理异常(以及 pop_back 列表)。然后该函数将提供 nothrow 保证,并且列表将始终包含好东西。

用户不会关心 100% CPU 和 100% RAM 之间的区别。当他们看到一个程序挂起时,他们会关闭其他程序,以便new找到足够的内存并继续。

我的问题:这可以实施吗?有没有等到内存可用的新方法?我可以在全球范围内应用它(例如 by #define new ...),以便 C++ 标准化之前的库可以在临时 100% RAM 中存活吗?

4

1 回答 1

2

这是一个有问题的设计,但您当然可以使用“新处理程序”来做到这一点。默认的 new-handler 只是简单地抛出std::bad_alloc. 如果 new-handler 返回,new将循环,并尝试再次分配。nothrow new 运算符也使用它,但在这种情况下std::bad_alloc,新处理程序抛出的 a 被捕获并NULL返回。

您只需new-handler 设置为您的自定义void (*)()处理函数。至少,你可能想让进程休眠一段时间——比如 1/10 秒。同样,程序可能无法继续运行 - 例如,Linux 具有可由管理员配置的“OOM 杀手”。

于 2013-12-03T07:13:52.900 回答