我个人不喜欢异常处理。在许多地方,建议不要将捕获异常并仍继续执行程序作为良好的编程习惯。

但是,由于 STL容器抛出异常(即bad_alloc),因此除了在我们的代码中具有异常处理块外,别无选择。但是,在我的应用程序中处理STL调用时,我发现很难使应用程序具有防泄漏性和鲁棒性。

下面的示例代码演示STL(带有异常处理)如何导致内存泄漏:

void my_function()
{
    try
    {
        std::vector<int> integers; // It can throw bad_alloc here (1)

        for (int i=0; i<10240; i++)
        {
            int* myintptr = new (std::nothrow) int;
            if (myintptr == NULL) // Memory not allocated. But no exception thrown so I am safe to continue.
                continue;
            *myintptr = i;
            integers.push_back (*myintptr ); // It can throw bad_alloc here (2)
            delete myintptr;
        }
    }
    catch(std::bad_alloc& ba)
    {
        // If it come here after throwing exception at (1) its fine. But if it has thrown exception at (2) then it just leaked memory allocated by new int
    }
}

(当然,这只是简化版本,以演示大型复杂代码中的类似情况。)

现在,这里可能有一些建议:

1.在最狭窄的块上使用异常处理:因此,这意味着我必须在调用push_back周围放置另一个try..catch。但是,如果我想在每个STL调用周围放置try ... catch块,我的代码将是什么样子?

2.确保您有足够的内存:也可能建议我们不要陷入OS无法分配内存的情况。因此,我们可以在进行STL调用之前主动检查是否有足够的内存。
但是这种策略并不总是可行的。拥有足够的可用内存并不能保证我们进一步分配内存的请求会成功(例如,假设内存碎片化。
另外,如果系统上正在运行其他消耗大量内存的应用程序,则OS可能很难在物理内存中找到要分配的空间,因此它可以拒绝该请求。)

因此,最后一个大问题是:

如何才能使我们的应用程序使用STL健壮(不会崩溃,即使OS拒绝内存分配请求也能保持运行)和充分证明(即使有异常也不会泄漏)?

最佳答案

您应该了解RAII!基本思想是,您永远不会拥有不受对象破坏的清理资源的任何资源。由于每当剩下一个块时都会调用局部变量的析构函数(除非使用诸如longjmp()之类的方法),所以这种方法完全自动化了清理工作。 RAII技术是为处理异常而部分开发的,但是即使没有抛出异常,我也发现这种编程风格可以显着减少资源泄漏。

顺便说一句,您强调的关于出现异常时不继续的建议绝对是胡说八道!另外,除了可以合理地重新开始操作的几个位置以外,您可能不会有任何try / catch块!当然,它们对于处理资源清理毫无用处,主要用于处理实际问题。

关于c++ - 当OS无法分配内存时,使用STL的应用程序是否应该易于发生内存泄漏?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23974216/

10-11 22:36
查看更多