有一个名为 foo 的方法有时会返回以下错误:
foo
一般情况下,您不能也不应该尝试对该错误作出响应。bad_alloc表示由于可用内存不足而无法分配资源。在大多数情况下,你的程序无法应对这种情况,而尽快终止是唯一有意义的行为。
bad_alloc
更糟糕的是,现代操作系统经常过度分配资源:在这种系统上,即使剩余的可用内存不足,malloc和new也能产生有效的指针--std::bad_alloc永远不会被抛出,或者至少不是内存耗尽的可靠信号。相反,如果尝试访问已分配的内存,就会导致分段故障,而这种故障是无法捕获的(你可以处理分段故障信号,但之后就无法恢复程序了)。
malloc
new
std::bad_alloc
当捕获到std::bad_alloc时,你唯一能做的也许就是记录错误,并尝试通过释放未释放的资源来确保程序安全终止(但如果程序适当使用 RAII,在抛出错误后的正常堆栈解卷过程中,堆栈解卷会自动完成)。
在某些情况下,程序可能会尝试释放一些内存并重试,或使用二级内存(= 磁盘)代替 RAM,但这些机会只存在于条件严格的特定场景中:
1.应用程序必须确保运行在不会超量分配内存的系统上,即在分配时就发出失败信号,而不是稍后再分配。 2.应用程序必须能够立即释放内存,在此期间不得再意外分配内存。
应用程序能控制第 1 点的情况极为罕见-- 用户空间应用程序从未**控制过,这是一个系统范围的设置,需要 root 权限才能更改;
好了,假设你已经解决了第 1 点。例如,您现在可以对部分数据使用 LRU 缓存(可能是一些可以按需再生或重新加载的特别大的业务对象)。接下来,您需要将可能失败的实际逻辑放到一个支持重试的函数中--换句话说,如果它被中止,您可以重新启动它:
lru_cache widget_cache; double perform_operation(int widget_id) { std::optional maybe_widget = widget_cache.find_by_id(widget_id); if (not maybe_widget) { maybe_widget = widget_cache.store(widget_id, load_widget_from_disk(widget_id)); } return maybe_widget->frobnicate(); } ... for (int num_attempts = 0; num_attempts < MAX_NUM_ATTEMPTS; ++num_attempts) { try { return perform_operation(widget_id); } catch (std::bad_alloc const&) { if (widget_cache.empty()) throw; // 内存错误。 如果是,widget_cache.remove_oldest(); } } // 在此处处理过多的失败尝试。
但即使在这里,使用 std::set_new_handler 代替处理 std::bad_alloc 也能带来同样的好处,而且会简单得多。
std::set_new_handler
1 如果你正在创建一个**控制点 1 的应用程序,并且你正在阅读本答案,请给我发一封电子邮件,我对你的情况真的很好奇。
你可以像捕捉其他异常一样捕捉它:
try { foo(); } catch (const std::bad_alloc&) { return -1; }
至于从这一点出发能做些什么,取决于你自己,但在技术上绝对是可行的。
我不建议这样做,因为 "bad_alloc "意味着内存*用完。最好的办法是放弃,而不是尝试恢复。不过,这就是你所要求的解决方案:
try { foo(); } catch ( const std::bad_alloc& e ) { return -1; }
一般情况下,您不能也不应该尝试对该错误作出响应。
bad_alloc
表示由于可用内存不足而无法分配资源。在大多数情况下,你的程序无法应对这种情况,而尽快终止是唯一有意义的行为。更糟糕的是,现代操作系统经常过度分配资源:在这种系统上,即使剩余的可用内存不足,
malloc
和new
也能产生有效的指针--std::bad_alloc
永远不会被抛出,或者至少不是内存耗尽的可靠信号。相反,如果尝试访问已分配的内存,就会导致分段故障,而这种故障是无法捕获的(你可以处理分段故障信号,但之后就无法恢复程序了)。当捕获到
std::bad_alloc
时,你唯一能做的也许就是记录错误,并尝试通过释放未释放的资源来确保程序安全终止(但如果程序适当使用 RAII,在抛出错误后的正常堆栈解卷过程中,堆栈解卷会自动完成)。在某些情况下,程序可能会尝试释放一些内存并重试,或使用二级内存(= 磁盘)代替 RAM,但这些机会只存在于条件严格的特定场景中:
1.应用程序必须确保运行在不会超量分配内存的系统上,即在分配时就发出失败信号,而不是稍后再分配。 2.应用程序必须能够立即释放内存,在此期间不得再意外分配内存。
应用程序能控制第 1 点的情况极为罕见-- 用户空间应用程序从未**控制过,这是一个系统范围的设置,需要 root 权限才能更改;
好了,假设你已经解决了第 1 点。例如,您现在可以对部分数据使用 LRU 缓存(可能是一些可以按需再生或重新加载的特别大的业务对象)。接下来,您需要将可能失败的实际逻辑放到一个支持重试的函数中--换句话说,如果它被中止,您可以重新启动它:
但即使在这里,使用
std::set_new_handler
代替处理std::bad_alloc
也能带来同样的好处,而且会简单得多。1 如果你正在创建一个**控制点 1 的应用程序,并且你正在阅读本答案,请给我发一封电子邮件,我对你的情况真的很好奇。
你可以像捕捉其他异常一样捕捉它:
至于从这一点出发能做些什么,取决于你自己,但在技术上绝对是可行的。
我不建议这样做,因为 "bad_alloc "意味着内存*用完。最好的办法是放弃,而不是尝试恢复。不过,这就是你所要求的解决方案: