Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ “写作”;“防止内存不足”;异常安全代码_C++_Exception_Out Of Memory - Fatal编程技术网

C++ “写作”;“防止内存不足”;异常安全代码

C++ “写作”;“防止内存不足”;异常安全代码,c++,exception,out-of-memory,C++,Exception,Out Of Memory,我正在编写一个类来保存图中连接组件的状态,支持动态连接,并且每次删除或添加新边时,我都必须重新计算相邻组件以连接或拆分它们 这些方法可以抛出的唯一例外是std::bad\u alloc。我的任何依赖项都不会引发其他异常。因此,唯一可能的例外是由于诸如std::unordered_set::insert或std::deque::push_back等方法的内存不足 这使我的算法的设计复杂了很多,因为我必须处理本地数据以保存差异,然后根据缓存的修改将所有修改移动到范围良好的try-catch块中 可读

我正在编写一个类来保存图中连接组件的状态,支持动态连接,并且每次删除或添加新边时,我都必须重新计算相邻组件以连接或拆分它们

这些方法可以抛出的唯一例外是
std::bad\u alloc
。我的任何依赖项都不会引发其他异常。因此,唯一可能的例外是由于诸如
std::unordered_set::insert
std::deque::push_back
等方法的内存不足

这使我的算法的设计复杂了很多,因为我必须处理本地数据以保存差异,然后根据缓存的修改将所有修改移动到范围良好的
try-catch
块中

可读性大大降低,思考和编写此异常安全代码的时间大大增加。此外,内存过度使用使得处理这种异常变得有点毫无意义

在这种情况下你会怎么做?如果内存确实不足,那么代码很可能会失败,但很可能以后会失败,整个程序也会失败,那么确保异常安全代码真的很重要吗


因此,简言之,考虑到正如一条评论所指出的,同样的异常抛出机制也可能耗尽内存,是否值得处理内存不足的异常?

正如您所建议的,在一个进程中优雅地处理内存不足的情况是极其困难和不可能的,取决于您正在运行的操作系统的内存行为。在许多操作系统上(例如Linux,当配置了默认设置时),内存不足的情况可能会导致进程在没有任何警告或追索的情况下被终止,无论您的代码如何小心地处理
bad\u alloc
异常

我的建议是让您的应用程序启动一个子进程(即,它可以作为子进程启动自己,使用一个特殊参数让子进程知道它是子进程而不是父进程)。然后父进程只是等待子进程退出,如果退出,则重新启动子进程


这样做的好处是,不仅可以从内存不足的情况中恢复,还可以帮助您从可能导致子进程崩溃或过早退出的任何其他问题中恢复。

几乎不可能在应用程序级别确保所需的OOM处理,特别是因为@StaceyGirl提到,无法保证您甚至能够抛出
std::bad\u alloc
。相反,管理内存分配更重要(也更容易)。通过使用内存池和智能指针模板,您可以实现以下几个优势:

  • 清洁代码
  • 内存分配可能失败的单一位置,因此应予以处理
  • 能够确保应用程序具有所需(或计划的)内存量
  • 优雅的堕落。由于您正在将“分配下一个内存块到池”事件与“从池中给我一些内存”请求分离,因此在关键时刻(
    std::unordered_set::insert
    等),您将能够优雅地处理它(而不是抛出异常),并且您的程序不会意外停止
如果内存不足,是否可以进行程序恢复?如果没有,谁在乎呢。只需让异常终止应用程序或在
main
中捕获它,并传递相应的错误消息。如果可以,那么您必须决定恢复点的位置,并让异常冒泡到那里。您应该知道,使用glibc,运行时甚至不能保证抛出
std::bad_alloc
。ABI要求在堆上分配异常,如果该分配失败,抛出线程将从紧急池中获取内存,如果使用嵌套异常,该内存很容易耗尽,在这种情况下,运行时会执行
std::terminate
并终止进程。看见简而言之,至少在Linux上,你不能用C++编写内存安全代码。您应该使用C,这是唯一的方法。@Peregring lk您可以声称您的代码只提供“基本的异常保证”,并保持一切简单。这就是大多数应用程序的编写方式。即使应用程序可以从OOM中恢复(这对于服务器来说很容易做到),它通常意味着与作业关联的整个上下文将被丢弃。强异常保证对于大多数用例来说太“强”。关于编辑,这取决于具体情况。例如,在GUI应用程序中,值得尝试回滚到导致问题的任何用户操作。对于一个终端应用程序来说,通常只做一件事,要么失败,要么成功,这样做可能不太值得。还要考虑您正在处理的资源类型。如果您需要刷新诸如提交数据库事务或优雅地关闭连接之类的内容,那么这会使它更有价值。如果您只使用内存并简单地输出一个结果,那么它可能不那么值得