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

我在学习new之后做了一些研究,与我习惯的malloc()不一样,不会因为失败的分配而返回NULL,并且发现有两种不同的方法来检查new是否成功。 这两种方法是:

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

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

我相信这两种方式能达到同样的目的(如果我错了,就纠正我),所以我的问题是:

这是检查new成功的更好select,完全基于可读性,可维护性和性能,而忽视事实上的c ++编程约定。

考虑你在做什么。 你正在分配内存。 如果由于某种原因内存分配不能工作,你assert 。 如果你只是让std::bad_alloc传播回main那么或多或less会发生什么。 在发布版本中, assert是无操作的,当你试图访问内存时,你的程序会崩溃。 所以,就像让exception冒泡:停止应用程序一样。

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

如果你实际上在你不能分配内存的情况下有一个特殊的代码path(也就是说,你实际上可以继续运行),那么exception可能是或者可能不是一种方法,这取决于代码path是什么。 如果代码path只是一个由空指针设置的开关,那么nothrow版本将会更简单。 相反,如果你需要做一些相当不同的事情(从一个静态缓冲区中取出,或者删除一些东西,或者其他的东西),那么捕获std::bad_alloc是相当不错的。

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

另一方面,如果你的程序绝对需要成功分配内存才能运行,可以使用try-catch来捕获(不一定在new附近)exception,并从程序中正常退出。

从纯粹的性能angular度来看,这一点很重要。 有exception处理的固有开销,尽pipe这种开销通常值得在应用程序可读性和维护方面进行折衷。 这种性质的内存分配失败不应该在应用程序的99%的情况下,所以这应该不经常发生。

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

所有这一切说,我通常接受exception抛出版本,因为通常我们的应用程序处于一个状态,如果内存分配失败,除了适当的错误消息,我们可以做的除了优雅退出,我们可以通过不需要NULL检查在我们新分配的资源上,因为根据定义,分配失败会将范围从重要的地方移出。

new用来创build对象,不分配内存,因此你的例子是有些人为的。

对象构造函数通常在失败时抛出。 在Visual Studio中经历了几次new实现之后,我不相信代码会捕获任何exception。 因此,在创build对象时寻找exception通常是有意义的。

认为只有当内存分配部分失败时才会抛出std::bad_alloc 。 我不知道会发生什么,如果你将std::nothrow传递给new但对象的构造函数抛出 – 我已阅读的文件中有歧义。

两种方法之间的性能差异可能是不相关的,因为大多数处理器时间可能很容易花费在对象构造函数或search堆中。

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