在try / catch块中新建(std :: nothrow)与New

时间:2011-09-01 23:09:38

标签: c++ performance exception-handling readability

我在学习new之后做了一些研究,不像我习惯的malloc(),对于失败的分配没有返回NULL,并且发现有两种不同的方法可以检查新的是否成功。这两种方式是:

try
{
    ptr = new int[1024];
}
catch(std::bad_alloc& exc)
{
    assert();
};

ptr = new (std::nothrow) int[1024];
if(ptr == NULL) 
    assert();

我相信这两种方式可以实现相同的目标,(如果我当然错了,请纠正我!),所以我的问题是:

这是检查new是否成功的更好选择,完全基于可读性,可维护性和性能,同时忽略了事实上的c ++编程约定。

4 个答案:

答案 0 :(得分:49)

考虑一下你在做什么。你正在分配内存。如果由于某种原因,内存分配无法正常工作,那么assert。如果您只是让std::bad_alloc传播回main,那么或多或少将会发生什么。在发布版本中,assert是无操作,程序在尝试访问内存时会崩溃。所以它就像让异常冒泡一样:暂停应用程序。

所以问自己一个问题:你真的需要关心如果内存不足会发生什么?如果你所做的只是断言,那么异常方法更好,因为它不会使你的代码混乱随机assert。您只需让异常回退到main

如果你确实在你无法分配内存的情况下有一个特殊的代码路径(也就是说,你实际上可以继续运行),异常可能会或可能不是一种可行的方式,具体取决于代码路径。如果代码路径只是一个指针为空的开关集,那么nothrow版本将更简单。相反,你需要做一些相当不同的事情(从静态缓冲区中取出,或者删除一些东西,或者其他东西),然后捕获std::bad_alloc非常好。

答案 1 :(得分:11)

这取决于分配发生的背景。如果您的程序即使分配失败也可以继续(可能会向调用者返回错误代码),然后使用std::nothrow方法检查NULL。否则你将使用控制流的例外,这不是一个好的做法。

另一方面,如果您的程序绝对需要成功分配内存以便能够运行,请使用try-catch来捕获(不一定在new附近)一个例外,并从程序中优雅地退出。

答案 2 :(得分:7)

从纯粹的表现来看,这很重要。异常处理存在固有的开销,尽管这种开销通常值得在应用程序可读性和维护方面进行权衡。这种性质的内存分配失败不应该在你的应用程序的99%的情况下,所以这应该不经常发生。

从性能角度来看,您通常希望避免使用标准分配器,因为它的性能相对较差。

所有这些说,我通常接受异常抛出版本,因为通常我们的应用程序处于一种状态,如果内存分配失败,我们除了优雅地使用适当的错误消息退出之外我们几乎无能为力,我们通过不保存性能需要NULL检查我们新分配的资源,因为根据定义,分配失败会将范围从重要的位置移出。

答案 3 :(得分:-3)

new用于创建对象,而不是分配内存,因此您的示例有点人为。

对象构造函数通常会在它们失败时抛出。在Visual Studio中多次执行new实现后,我不相信代码会捕获任何异常。因此,在创建对象时查找异常通常是有意义的。

认为只有在内存分配部分失败时才会抛出 std::bad_alloc。我不确定如果将std::nothrow传递给new会发生什么,但对象构造函数会抛出 - 我读过的文档中存在歧义。

两种方法之间的性能差异可能无关紧要,因为大多数处理器时间可以很容易地花在对象构造函数中或搜索堆中。

经验法则并不总是合适的。例如,实时系统通常会限制动态内存分配,因此new(如果存在)可能会过载。在这种情况下,它可能会使用返回的空指针并在本地处理失败。