CComPtr 和引用计数
CComPtr and reference count
我正在使用 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 时,它将共享该指针的所有权并增加引用计数。要在不增加引用计数的情况下获取指针的所有权,请使用 CComPtr::Attach method.
CComPtr<ID2D1Bitmap> bitmap;
bitmap.Attach(create_bitmap(bitmapSize));
有了 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 class 将在您传递指针的过程中准确地管理引用:局部变量、return 值、新的局部值。在 Release 版本中优化编译器也会删除一些多余的 AddRef/Releases,因此您不必太担心它们。
这段代码有很多问题。
第一个问题是次要的,但它可能会导致很多误解。 AddRef()
和 Release()
是 not actually required to return any sensible values。所以他们 return 实际引用计数很好,但你不能每次都依赖它。所以基本上你的 count_ref()
功能是幼稚和不可靠的。
现在假设 Release()
return 是真正的引用计数,显然 create_bitmap()
return 是一个已经将其引用计数设置为 1 的对象。然后 CComPtr
调用 AddRef()
并且引用计数变为 2。然后当 CComPtr
超出范围时,它的析构函数调用 Release()
然后没有更多指向对象的指针并且它被泄露了。
后一个问题的解决方案是使用 CComPtr::Attach()
获取由 create_bitmap()
编辑的对象 return 的所有权,而无需再次调用 AddRef()
:
CComPtr<ID2D1Bitmap> bitmap;
bitmap.Attach(create_bitmap(bitmapSize));
这将使代码工作,但它不是很清楚并且可能比必要的更难维护。如果您负担得起更改 create_bitmap()
签名,那么最好将其更改为 returns CComPtr
,如 中所建议的那样。这清楚地表明,调用者必须将对象的所有权授予任何看到函数签名的人,并且无需使用单独的调用 Attach()
.
我正在使用 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 时,它将共享该指针的所有权并增加引用计数。要在不增加引用计数的情况下获取指针的所有权,请使用 CComPtr::Attach method.
CComPtr<ID2D1Bitmap> bitmap;
bitmap.Attach(create_bitmap(bitmapSize));
有了 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 class 将在您传递指针的过程中准确地管理引用:局部变量、return 值、新的局部值。在 Release 版本中优化编译器也会删除一些多余的 AddRef/Releases,因此您不必太担心它们。
这段代码有很多问题。
第一个问题是次要的,但它可能会导致很多误解。 AddRef()
和 Release()
是 not actually required to return any sensible values。所以他们 return 实际引用计数很好,但你不能每次都依赖它。所以基本上你的 count_ref()
功能是幼稚和不可靠的。
现在假设 Release()
return 是真正的引用计数,显然 create_bitmap()
return 是一个已经将其引用计数设置为 1 的对象。然后 CComPtr
调用 AddRef()
并且引用计数变为 2。然后当 CComPtr
超出范围时,它的析构函数调用 Release()
然后没有更多指向对象的指针并且它被泄露了。
后一个问题的解决方案是使用 CComPtr::Attach()
获取由 create_bitmap()
编辑的对象 return 的所有权,而无需再次调用 AddRef()
:
CComPtr<ID2D1Bitmap> bitmap;
bitmap.Attach(create_bitmap(bitmapSize));
这将使代码工作,但它不是很清楚并且可能比必要的更难维护。如果您负担得起更改 create_bitmap()
签名,那么最好将其更改为 returns CComPtr
,如 Attach()
.