Sign in to follow this  
Trillian

IDirect3DDevice9 references (&)

Recommended Posts

Hello! Is it a good idea to use & references to a IDirect3DDevice9 ? What I'd like to do is to have (almost) all of my class constructors that need a IDirect3DDevice9 reference so that they are sure the device is okay :
class hello
{
private:
  IDirect3DDevice9 & m_Device;

public:
  hello(IDirect3DDevice9 & device) : m_Device(device) {}
};

function foo()
{
LPDIRECT3DDEVICE9 my_super_device;
// CreateDevice to my_super_device

hello my_hello(*my_super_device);
// use hello
}

Will that cause problems, because IDirect3DDevice9 is an interface? And is there some reason why this wouldn't be a good idea?

Share this post


Link to post
Share on other sites
Every time you do:

LPDIRECT3DDEVICE9 dev2 = dev1;

you are supposed to increment the reference count. If dev2 is a reference then you
don't need to. I guess you can.

I would recommend using a com_ptr which handles the reference counting for sharing COM objects around. My com_ptr is below:


#ifndef COM_PTR_H
#define COM_PTR_H

#include <assert.h>

template < typename T >
class com_ptr
{
typedef T* _pT;

public:
// copy constructor from an object pointer
com_ptr( T* other = 0)
:
_p( 0 )
{
_p = other;
AddRef();
}
// copy constructor from another com_ptr
com_ptr( const com_ptr< T >& other )
:
_p( 0 )
{
_p = other.Get();

AddRef();
}

~com_ptr()
{
Release();
}
// assignment from T*
com_ptr< T >& operator=( T* rhs )
{
Release();

_p = rhs;

return *this;
}
// assignment from T* reference
com_ptr< T >& operator=( _pT& rhs )
{
Release();

_p = rhs.Get();

AddRef();

return *this;
}
// assignment from another com_ptr
com_ptr< T >& operator=( com_ptr< T >& rhs )
{
// Release this
Release();

_p = rhs.Get();

AddRef();

return *this;
}
// Dereferencing
T* operator->()
{
return _p;
}

T& operator*()
{
return *_p;
}

T** operator&()
{
return &_p;
}
// Increment the reference count
void AddRef()
{
if ( _p )
{
_p->AddRef();
}
}
// Decrement the reference count
void Release()
{
if ( _p )
{
_p->Release();
}
}
// Reset
void Reset()
{
Release();
_p = NULL;
}

T* Get() const
{
return _p;
}

unsigned long Ref()
{
if ( _p )
{
_p->AddRef();
return _p->Release();
}

return 0;
}
private:

T* _p;
};
#endif


Hope that helps,

Dave

Share this post


Link to post
Share on other sites
I understand your idea of reference counting, if I'm not mistaking, it is used so that the object is deleted only when all references to it are deleted.

However, in my application, only the main app will Release() the device, all the other pointers are "read-only", in that situation, do I really need to have a reference count?

Share this post


Link to post
Share on other sites
It's fine. Note that you might cause interesting crashes if the device is ever lost or needs to be recreated and you forget to refresh all your references... If you're careful, it'll work out fine, but it's not commonly done because references are immutable: if you need to recreate your device, you'd also need to recreate all of your objects that held references to the old device, losing any data they might have.

It gets messy quick, all because you didn't want a little pointer.

And, as Dave pointed out, you should use com_ptr or ATL's CComPtr wrappers.

Share this post


Link to post
Share on other sites
Well it would be good practice to implement the COM pointer anyways. But for an application that is equally as simple as the first few D3D tutorials then there isn't alot of point. using com_ptr would be a bit more future-proof as well.

Dave

Share this post


Link to post
Share on other sites
There are cases where you NEED to release and re-create the device -- just Reset() won't clear it. Thus, you should write your application so that it allows the device to be released and re-created. This means writing some little pattern in your system that receives notifications about the device changing, and doing the right thing in response.

When you store a reference to a COM object (texture, vertex buffer, device, effect, etc), you should ALWAYS store it in a CComPtr<> (from <atlbase.h>). If you store it anywhere else, you'll probably end up with resource leaks or bad release behavior.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this