【问题标题】:CComPtr and reference countCComPtr 和引用计数
【发布时间】:2017-09-10 17:33:02
【问题描述】:

我正在使用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.

【问题讨论】:

  • 使用 CComPtr::Attach() 获取接口指针的所有权。

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


【解决方案1】:

使用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,因此您不必太担心它们。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      这段代码有很多问题。

      问题是次要的,但可能会导致很多误解。 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() 签名的费用,那么最好将其更改为返回CComPtr,如the other answer 中所建议的那样。这清楚地表明,调用者必须将对象的所有权交给任何看到函数签名的人,并且无需单独调用 Attach()

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-31
        • 2014-12-28
        • 2012-03-03
        • 2011-02-12
        • 2010-09-24
        • 2012-06-27
        • 1970-01-01
        • 2016-01-02
        相关资源
        最近更新 更多