2017-04-14 3 views
1

J'utilise des objets de type CComPtr. Mais j'ai quelques problèmes de fuite de mémoire. En particulier, j'ai le code suivant:CComPtr et compte de référence

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

Où:

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

    return 0; 
} 

Et:

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

    return bitmap; 
} 

Je me attendais à une valeur de n égale à 1, mais il est en fait égal à 2. Pourquoi le nombre de références de mon CComPtr n'est pas 1? Puis-je utiliser correctement mon objet CComPtr?

Et quand le processus se termine, je reçois la fuite de mémoire suivante:

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

Prendre possession du pointeur d'interface avec CComPtr :: Attach(). –

Répondre

3

Avec CComPtr vous aurez rarement besoin d'utiliser des types de pointeurs d'interface brute.

Vous pouvez le faire de cette façon, par exemple:

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(...); 
... 

classe CComPtr va gérer les références avec précision le long de la façon dont vous passez les pointeurs: variable locale, la valeur de retour, nouvelle valeur locale. L'optimisation du compilateur dans les versions Release supprime également certaines addRef/releases excessives, vous n'avez donc pas besoin de vous en soucier.

2

Lorsque vous construisez CComPtr du pointeur, il partagera la propriété de ce pointeur et le nombre de référence incrément. Pour devenir propriétaire du pointeur sans incrémenter le nombre de références, utilisez CComPtr::Attach method.

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

Ce code présente un certain nombre de problèmes.

Le premier numéro est mineur mais il peut mener à beaucoup de malentendu. AddRef() et Release() sont not actually required to return any sensible values. Il est donc bon qu'ils renvoient le nombre de références réel, mais vous ne pouvez pas compter sur cela à chaque fois. Donc, fondamentalement, votre fonction count_ref() est naïf et peu fiable.

Maintenant, en supposant que Release() renvoie le nombre réel de références, il est clair que create_bitmap() renvoie un objet dont le compteur de références est déjà défini sur 1. Puis CComPtr appelle AddRef() et le nombre de références change à 2. Ensuite, lorsque CComPtr sort de la portée de son destructeur appelle Release() et puis il n'y a plus de pointeurs vers l'objet et il obtient une fuite.

La solution au problème plus tard serait d'utiliser CComPtr::Attach() juste prendre possession de l'objet retourné par create_bitmap() sans avoir AddRef() appelé encore une fois:

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

qui rendrait le travail de code, mais ce n'est pas très clair et peut-être un peu plus difficile à maintenir que nécessaire. Si vous pouvez vous permettre de changer la signature create_bitmap() alors il serait préférable de le changer afin qu'il renvoie CComPtr comme suggéré dans the other answer.Cela indique clairement que l'appelant doit prendre possession de l'objet à quiconque voit la signature de la fonction et qu'il n'est pas nécessaire d'utiliser des appels distincts au Attach().