在C ++中抛出异常时释放本地缓冲区

时间:2011-12-06 19:59:54

标签: c++ exception constructor buffer free

假设我在C ++类中有以下构造函数:

MyClass::MyClass()
{
    char* buffer = malloc(100);
    if (0 != someD3DXCallThatCanFail(..., buffer, ...))
    {
        free(buffer);
        throw MyException(L"some message");
    }
    char* buffer2 = malloc(200);
    if (0 != anotherD3DCallThatCanFail(..., buffer2, ...))
    {
        free(buffer);
        free(buffer2);
        throw MyException(L"another message");
    }
    .. more code here where buffer and buffer2 are still used

    free(buffer);
    free(buffer2);
}

编辑:我讨厌malloc / free和new / delete,但不幸的是我需要使用缓冲区来加载纹理,然后将纹理传递给ID3D10ShaderResourceView,ID3D10Buffer,顶点缓冲区等。所有这些都需要指向缓冲区的指针。

我尝试使用异常而不是返回错误代码。 我还想在需要它们的地方创建缓冲区,并在不再需要它们之后立即释放它们。

然而,看起来很难看的是,如果出现错误,无论我是否返回错误代码或抛出异常,我仍然应该记得清理到那时为止创建的任何缓冲区。如果我有10个缓冲区和10个可能的错误点,我将不得不调用free()100次(在每个错误情况下都要记得释放每个缓冲区)。

现在假设我或者更糟,我的同事想要改变一些逻辑,比如说,在中间的某处添加另一个缓冲区。现在,他必须通过方法的其余部分查看可能发生的所有错误,并在每个这样的位置为该缓冲区添加free()。如果他赶时间,他可以很容易地忽略一些这样的地方,并且你有内存泄漏。

这也极大地破坏了代码。

finally关键字可以解决Java或C#中的问题。无论代码在哪里发生异常,我仍然会在“finally”中清理所有缓冲区(顺便说一句,你不需要使用垃圾收集)。在我理解的C ++中,我可能必须为任何这样的缓冲区创建一个成员变量,并在析构函数中确保清理缓冲区。看起来对我来说也很难看,因为名为“pBuffer”的成员变量,即使是私有变量,也只是垃圾,因为它只在一个方法中使用(在本例中是构造函数),并且其余部分始终为NULL。时间。

必须是常见问题,但我无法使用搜索找到答案。谢谢!

6 个答案:

答案 0 :(得分:8)

手动停止管理内存,您不会遇到这些问题。使用类似std::vector<char>的内容。

或者,你可以使用Boost的shared_array之类的东西,但这对你在这里尝试做的事情来说太过分了:

http://www.boost.org/doc/libs/1_41_0/libs/smart_ptr/shared_array.htm

这里更常见的一点是你应该使用RAII习语 - 也就是说,当你获得资源时,你将它们存储在一个类的实例中,它的析构函数再次释放它们。然后,然而,该资源拥有类的实例超出范围,保证资源被释放。

见这里:

http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

答案 1 :(得分:4)

规范的答案是“资源获取是初始化”(RAII)和智能指针的原则。您在堆栈上创建一个类实例,它将释放其析构函数中的内存,例如: boost::scoped_ptr

答案 2 :(得分:2)

相反,请使用raii

MyClass::MyClass()
{
    std::vector<char> buffer(100);
    if (0 != someD3DXCallThatCanFail(...))
    {
        throw MyException(L"some message");
    }
    std::vector<char> buffer2c(200);
    if (0 != anotherD3DCallThatCanFail(...))
    {
        throw MyException(L"another message");
    }
    .. more code here 
}

答案 3 :(得分:1)

使用惯用的C ++方法:RAII。这个维基百科页面有C ++样本。

答案 4 :(得分:1)

再次搜索“C ++智能指针”。你需要在内存而不是原始malloc上使用异常安全的包装器,正如你所指出的那样带来了很多麻烦,顺便说一下,operator new可能会更好地替换现在你正在编写C ++而不是C代码。

上一个答案here涵盖了这一领域。

答案 5 :(得分:1)

对此的规范答案将是C ++ 11中的unique_ptr。在那之前,可能scoped_ptr(http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/scoped_ptr.htm)单身人士和scoped_array(http://www.boost)来自Boost的数组的.org / doc / libs / 1_47_0 / libs / smart_ptr / scoped_array.htm)。或者您可以自己编写等效代码。