CComPtr和引用计数

时间:2017-04-14 12:48:24

标签: c++ memory-leaks com atl direct2d

我正在使用CComPtr类型的对象。但我有一些内存泄漏问题。特别是,我有以下代码:

CComPtr<ID2D1Bitmap> bitmap = create_bitmap(bitmapSize);
auto n = count_ref((ID2D1Bitmap*)bitmap);

其中:

template<class Interface>
ULONG count_ref(Interface* pInterface) noexcept
{
    if (pInterface)
    {
        pInterface->AddRef();
        return pInterface->Release();
    }

    return 0;
}

并且:

ID2D1Bitmap* create_bitmap(const D2D1_SIZE_U& size)
{
    ID2D1Bitmap* bitmap;
    CreateBitmap(&bitmap);

    return bitmap;
}

我期待n的值等于1,但它实际上等于2.为什么CComPtr的引用计数不是1?

我是否正确使用了我的CComPtr对象?

当进程终止时,我得到以下内存泄漏:

An interface [072B1F50] was created but not released. Use 'dps 072B1F20' to view its allocation stack.
Object type: ID2D1Bitmap
    Device-dependent size: 1000 x 600
    Device-independent size: 1000.00 x 600.00
    Format: DXGI_FORMAT_B8G8R8A8_UNORM
    Alpha mode: D2D1_ALPHA_MODE_PREMULTIPLIED
    Outstanding reference count: 1

D2D DEBUG ERROR - Memory leaks detected.

3 个答案:

答案 0 :(得分:3)

使用CComPtr,您很少需要使用原始接口指针类型。

你可以这样做,例如:

CComPtr<ID2D1Bitmap> create_bitmap(const D2D1_SIZE_U& size)
{
    CComPtr<ID2D1Bitmap> bitmap;
    CreateBitmap(&bitmap); // Declared as CreateBitmap(ID2D1Bitmap**);
    return bitmap;
}

CComPtr<ID2D1Bitmap> pBitmap = create_bitmap(...);
...

CComPtr类将按照传递指针的方式准确地管理引用:局部变量,返回值,新本地值。在Release版本中优化编译器也会删除一些过多的AddRef / Releases,因此您不必担心它们。

答案 1 :(得分:2)

从指针构造CComPtr时,它将共享此指针的所有权并增加引用计数。要在不增加引用计数的情况下获取指针的所有权,请使用CComPtr::Attach method

CComPtr<ID2D1Bitmap> bitmap;
bitmap.Attach(create_bitmap(bitmapSize));

答案 2 :(得分:1)

此代码存在许多问题。

问题一是次要的,但可能导致很多误解。 AddRef()Release()not actually required to return any sensible values。所以他们返回实际的参考计数是好的,但你不能每次都依赖它。所以基本上你的count_ref()函数天真且不可靠。

现在假设Release()返回实际引用计数,很明显create_bitmap()返回一个已将其引用计数设置为1的对象。然后CComPtr调用AddRef()并将引用计数更改为2.然后,当CComPtr超出范围时,析构函数调用Release(),然后没有更多指向该对象的指针它被泄露了。

后一个问题的解决方案是使用CComPtr::Attach()来获取create_bitmap()返回的对象的所有权,而无需再次调用AddRef()

CComPtr<ID2D1Bitmap> bitmap;
bitmap.Attach(create_bitmap(bitmapSize));

这将使代码工作,但它不是很清楚,也许比必要的维护更难。如果您能够承担更改create_bitmap()签名的费用,那么最好更改它,以便按照the other answer中的建议返回CComPtr。这清楚地表明调用者必须将对象的所有权归给任何看到函数签名的人,并且不需要单独调用Attach()