2017-04-14 119 views
1

我正在使用CComPtr类型的对象。但我有一些内存泄漏问题。特别是,我有以下代码: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. 
+0

通过CComPtr :: Attach()获取接口指针的所有权。 –

回答

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,因此您无需担心太多。

2

当您从指针构建但是CComPtr将分享这个指针和增量引用计数的所有权。要获取指针的所有权而不增加引用计数,请使用CComPtr::Attach method

CComPtr<ID2D1Bitmap> bitmap; 
bitmap.Attach(create_bitmap(bitmapSize)); 
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()签名,那么最好更改它,以便返回CComPtr,如the other answer中所建议的那样。这就清楚地表明,调用者必须将对象的所有权交给任何看到函数签名的人,并且不需要对Attach()单独调用。