在阅读this question之前,我从未认真对待异常处理。现在我看到了必要性,但仍然觉得“编写异常安全代码非常困难”。
在该问题的接受答案中查看此示例:
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
轻松提供基本保证。但是当我抓到std::bad_alloc
时,我不知道它是否发生在push_back
或x->doSomethingThatCanThrow()
中,所以我不知道t.list是否仍然“好”或者它最后一个元素没有完全准备好。然后唯一的选择是丢弃t,显示可怕的消息并中止,如果t对整个程序是必不可少的。
具有强保证的代码没有问题,但“它可能变得昂贵”(此示例涉及大型列表的副本),并且不那么可读。
可能的解决方案可能是让new
等待内存可用,删除最烦人的异常std::bad_alloc
。然后2.和3.不会抛出(提供X
的构造和复制总是成功)。我可以在try块中包装4.并在这里处理异常(和pop_back列表)。然后该函数将提供nothrow保证,列表将始终包含好东西。
用户不会关心100%CPU和100%RAM之间的区别。当他们看到程序挂起时,他们将关闭其他程序,以便new
找到足够的内存并继续。
我的问题:这可以实施吗?是否有一个新的等待直到内存可用?我可以全局应用它(例如通过#define new ...
),因此在C ++标准化之前的库可以在临时的100%RAM中存活吗?
答案 0 :(得分:2)
这是一个有问题的设计,但你肯定可以用'new-handler'来做到这一点。默认的新处理程序只会抛出std::bad_alloc
。如果new-handler返回,new
将循环,并尝试再次分配。 nothrow new运算符也使用它,但是捕获了new-handler抛出的std::bad_alloc
,并返回NULL
。
您只需要set自定义void (*)()
处理函数的新处理程序。至少,你可能想让这个过程暂停一段时间 - 比如1/10秒。同样,程序可能无法继续 - 例如,Linux具有可以由管理员配置的“OOM杀手”。