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

Ann*_*inn 39 c++ performance readability exception-handling

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

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

ptr = new (std::nothrow) int[1024];
if(ptr == NULL) 
    assert();
Run Code Online (Sandbox Code Playgroud)

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

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

Nic*_*las 49

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

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

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

  • 这是一个非常令人信服的论点,我不知道异常可能会爬上调用堆栈以找到一个catch块.......我不知道有很多例外情况可以做.可能是时候我终于在这些年后学会了它,啊哈 (3认同)

Pra*_*ian 12

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

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

  • 这是一个很好的答案.它总结了整个例外的理念:在异常情况下使用例外,并在可以有意义地处理它们的地方捕捉它们.另一方面,对于您可以并且想要在本地处理的非异常运行时情况,请不要使用异常. (4认同)

Cha*_*had 7

从纯粹的性能角度来看,它很重要.异常处理存在固有的开销,尽管这种开销通常值得在应用程序可读性和维护方面进行权衡.这种性质的内存分配失败不应该在您的应用程序的99%情况下,因此这种情况很少发生.

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

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

  • 在GCC实现中,异常不会花费你任何东西(除了可能稍差的内存局部性)如果它们没有被使用 - 你只需在实际抛出异常时付费. (2认同)