With the release() function's return values,

Started by
8 comments, last by Cygon 19 years, 6 months ago
Hi, I'm writing basic classes around a few of the directx's ones, and I've got alot of debug error output messages. I am wondering if I should have the release() function a part of output debug messages. Like does the return value being 2 matter or it equalling -1 or 0. (these are recent values i have gotten) So does it matter what the Release() function outputs? Thanks
Advertisement
If the IUnknown interface is properly implemented in a class, then a return value of less than zero for Release() means that you call it too many times in the client. Note that while this is a "standard", not all COM classes actually get this right.

Most Release() implementations check if the class' internal reference count is 0 during the release function, and if it is, deletes the class and/or releases it's internal resources.

SAFE_RELEASE is a convenient macro for your situation, if you manage to call at least the amount of "releases" needed.

Niko Suni

Quote:From MSDN
IUnknown::Release
Decrements the reference count for the calling interface on a object. If the reference count on the object falls to 0, the object is freed from memory.

ULONG Release(void);

Return Value
Returns the resulting value of the reference count, which is used for diagnostic/testing purposes only. If you need to know that resources have been freed, use an interface with higher-level semantics.
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas only, and not for things themselves." - John Locke
For DirectX COM interfaces, Release() returns the value of the reference count *after* the release has executed.

So if an object still has references, the return value will be > 0.

This behaviour is only really for debugging purposes, so make sure you don't rely on it in production/release build code!!


The Break on AllocID and related functionality of the DirectX control panel applet and debug runtimes are usually better for locating leaks. A parent COM object such as a D3D device can be refcounted by subordinate interfaces such as a texture, so a non-zero refcount when you Release() your device interface doesn't necessarily mean you forgot to release the device - the culprit may be elsewhere!

[EDIT: bah, too late again![smile]]

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

Could someone explain the whole reference thing to me?

Right now I think its just to pass off the same object in memory under different pointers?

And if so, why would you need to do that?

Thanks
Quote:Original post by johnnyBravo
Could someone explain the whole reference thing to me?

Right now I think its just to pass off the same object in memory under different pointers?

And if so, why would you need to do that?

Thanks



The SDK docs explain it:

DirectX Documentation for C++ ->
The DirectX Software Development Kit ->
DirectX Programming Guide ->
Using COM ->
Managing a COM Object's Lifetime


Basically it's so you can't do things like accidentally delete a texture which a D3D device is currently using for rendering, and so that system resources can be shared between multiple clients...

...the SetTexture() call increases the reference count on the texture you specify by 1; then when the device has finished with the texture or another texture is set in that slot, it decreases the reference count by 1...

...Imagine your code had a bug in it which called Release() (maybe called from a destructor in your wrapper etc) on the texture while it was still being used by the device:

- if there wasn't any reference counting, then the texture would be removed from memory straight away even though the device is still referring to that memory - the result? boom!, crash.

- with reference counting, because the refcount was incremented to 2 by SetTexture(), your Release() call simply decrements the refcount by 1 and returns (the actual destruction of the texture in memory only happens when the refcount is 0). Then, when the device has finished rendering or another texture is set, then Release() will be called again and the texture will be removed because the refcount is 0.

Effectively reference counting "delays destruction of resources until a time when it's safe to do so".

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

Ah I see, also does it matter in what order you release objects?

E.g. Say I released the Direct3dDevice class before I released the Direct3d class, or

released the Direct3dDevice class before I released the texture class.

Would these cause a problem?

also at this stage the program wouldnt be running a loop anymore.

Thans
Quote:Original post by johnnyBravo
Ah I see, also does it matter in what order you release objects?


In practice, this does matter. It is not absolutely guaranteed that the objects follow the COM protocol nicely, as they should. Incidentally, mainly for this reason, the return value of Release() is to be considered only advisory - even though most of the DX code (for example) handle it right.

Niko Suni

Quote:Original post by Nik02
Quote:Original post by johnnyBravo
Ah I see, also does it matter in what order you release objects?


the return value of Release() is to be considered only advisory


So if the Release() returns 2, I shoundn't worry about calling it again until it equals 0?

Thanks
You should never do that. Just call Release() everytime you let go of an COM object for which the reference count has been increased (otherwise said, ownership has been transferred to you). The reference counter is increased whenever a DirectX function returns a pointer to an object (eg. Direct3DCreate9(), IDirect3DDevice9::CreateTexture() and so on).

A good way to ensure correct semantics when working with reference counting is to use smart pointers. Direct3D already defines a set of smart pointers when you include the "comdef.h" header before "d3d9.h":

#include <comdef.h>#include <d3d9.h>void foo() {  IDirect3D9Ptr spD3D9(Direct3DCreate9(D3D_SDK_VERSION));  IDirect3DDevice9Ptr spD3DDevice;  spD3D9->CreateDevice(..., &spD3DDevice);  // spD3DDevice will be automatically released  // spD3D9 will automatically be released}


-Markus-
Professional C++ and .NET developer trying to break into indie game development.
Follow my progress: http://blog.nuclex-games.com/ or Twitter - Topics: Ogre3D, Blender, game architecture tips & code snippets.

This topic is closed to new replies.

Advertisement