如何释放由Gdiplus :: Bitmap :: FromFile分配的内存

4

如果我使用delete或::delete,会触发C++异常。

当然,我可以不进行删除操作,程序运行良好,但这样会导致内存泄漏问题迅速增加。

我的代码如下(包括与gdi+相关的任何内容):

#include <windows.h>

#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif

namespace Gdiplus
{
    using std::min;
    using std::max;
}
#include <gdiplus.h>
#pragma comment (lib,"Gdiplus.lib")

namespace Infra
{
    namespace Color
    {
        //more app code


        void CrashingMethod(...)
        {
            Gdiplus::Bitmap* bitmap = Gdiplus::Bitmap::FromFile(PNG_PATH);

            //read bitmap
            int qpWidth = frameWidth / 16;
            Gdiplus::Color color = Gdiplus::Color();

            for (unsigned int y = 0, qy = (frameHeight / 16) - 1; y < frameHeight; y += 16, qy--)
            {
                for (unsigned int x = 0, qx = 0; x < frameWidth; x += 16, qx++)
                {
                    bitmap->GetPixel(x, y, &color);

                    byte red = color.GetRed();

                    //do stuff with the red channel

                }
            }

            delete bitmap; //this line will randomly crash. Not always, not in all machines
            bitmap = NULL;
        }
    }


    }
}

什么是正确的释放方法?我知道删除gdi+位图存在问题,但使用::delete的解决方案并没有使其变得更好。与我看到的解决方案不同,我不是使用new来创建位图,而是使用"FromFile"。此外,正如您所看到的,我没有使用"namespace Gdiplus",因此该命名空间不在作用域内,我需要显式引用它(这可能会改变事情)。

等等,你的代码里到处都是 Gdiplus::,并且包含了 <gdiplus.h>,但你却没有使用 Gdiplus 命名空间?那你用的是什么替代品呢?如果你确定你没有使用这个命名空间,那就得看看你用的是什么替代品了。 - andlabs
2
Gdi+对象(如Bitmap)派生自GdiPlusBase,旨在通过new和delete进行管理。似乎更有可能是您在其他地方存在内存溢出,破坏了堆栈,在释放时导致随机崩溃。 - Chris Becke
andlabs。我应该重新表述一下。我没有使用“namespace Gdiplus”,因此该命名空间不在范围内,我需要显式地引用它。我会在描述中修复它。 - cloudraven
Chris,我读到gdiplus定义了自己的new和delete运算符。我看到有人遇到了问题。我想也许这个问题与此有关。你知道我应该使用哪个版本的运算符吗? - cloudraven
在离开作用域之前将 bitmap 设置为 NULL 似乎是毫无意义的。编译器肯定会在任何情况下优化掉它。 - David Heffernan
1
我有点确定,你不会得到一个C++异常,而是一个失败的断言或SEH异常(更多细节将会有所帮助)。例如,当newdelete在不同的堆上操作时就会发生这种情况(请参见跨DLL边界传递CRT对象的潜在错误)。为了防止这种情况,你的应用程序必须动态链接到与GDI+使用相同的CRT。无关紧要的是,如果你不想让min/max被定义为宏,那么在包含Windows.h之前,可以#define NOMINMAX - IInspectable
1个回答

2
您创建和删除位图对象的方式是正确的。但是您的程序中有另一个缺陷导致了堆的破坏,需要找到并修复该缺陷。
堆破坏可能会让人感到困惑。缺陷可以存在于代码的某个部分,但运行时错误只会出现在另一个与之相关性不大的部分。调试难度较大,您可能会发现使用工具会很有用:Is there a good Valgrind substitute for Windows?

这是堆破坏,实际上发生在代码的那个循环中。qy的值变成了负数,由于它是无符号数,变成了一个比我正在访问的数组长度还要大的值。 - cloudraven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接