smart pointer with custom deconstruction?

C

Christopher

I have a need to create a method that allocates something, but niether
the method or the class is responsible for managing its lifetime. I
feel like returning a raw pointer is a bad idea. So, I thought that I
could wrap it up in a smart poiner of some kind. However, the thing
that I am allocating is from a COM object, so I cannot just call
delete on it, instead if reuqires I call it's Release() method. Is
there any kind of pointer class in existance already there I can
customize its destruction to call the Release method on my allocated
object?

I just don't want my reviewer gasping at my returning a raw pointer.
 
K

Kai-Uwe Bux

Christopher wrote:

[snip]
Is there any kind of pointer class in existance already there I can
customize its destruction to call the Release method on my allocated
object?
[snip]

Sure: both, tr1::shared_ptr and boost::shared_ptr allow for a custom
deleter. You pass the deleter as an argument upon construction of the
shared_ptr.


Best

Kai-Uwe Bux
 
C

Christopher

Christopher wrote:

[snip]> Is there any kind of pointer class in existance already there I can
customize its destruction to call the Release method on my allocated
object?

[snip]

Sure: both, tr1::shared_ptr and boost::shared_ptr allow for a custom
deleter. You pass the deleter as an argument upon construction of the
shared_ptr.

A question related to this is:
If I have a hierarchy of objects that need to use the object I got a
smart pointer for, but only one manages its lifetime, would it be best
practice to pass and store a reference in each dependant or pass and
store the smart pointer?

I know there is some tiny overhead with smart pointers, but the number
of objects that are going to use it is tremendous. It is used in
almost every class in my project, with possibly up to 5k or so
instances. I know one person's opinion at work was to just store a
reference while others passed the smart pointer around. What are your
thoughts?

P.S.
Kai-Uwe - You have been a tremendous help in a number of posts. You
rock!
 
T

Thomas J. Gritzan

Christopher said:
I have a need to create a method that allocates something, but niether
the method or the class is responsible for managing its lifetime. I
feel like returning a raw pointer is a bad idea. So, I thought that I
could wrap it up in a smart poiner of some kind. However, the thing
that I am allocating is from a COM object, so I cannot just call
delete on it, instead if reuqires I call it's Release() method. Is
there any kind of pointer class in existance already there I can
customize its destruction to call the Release method on my allocated
object?

If you don't mind using ATL, the obvious choice would be CComPtr. This
smart pointer is designed to handle COM objects and has smaller overhead
since it's an intrusive pointer.
Please ask futher specific questions on ATL and COM in a Microsoft
newsgroup, since it is hardly on-topic here.

If you don't want to use ATL, then another intrusive smart pointer like
boost::intrusive_ptr would be the next best idea, since COM objects
already carry a reference count.

Intrusive pointers are small, essentially they only hold the actual raw
pointer, incrementing or decrementing the reference count when copied or
destroyed.
 
K

Kai-Uwe Bux

Christopher said:
Christopher wrote:

[snip]> Is there any kind of pointer class in existance already there I
[can
customize its destruction to call the Release method on my allocated
object?

[snip]

Sure: both, tr1::shared_ptr and boost::shared_ptr allow for a custom
deleter. You pass the deleter as an argument upon construction of the
shared_ptr.

A question related to this is:
If I have a hierarchy of objects that need to use the object I got a
smart pointer for, but only one manages its lifetime, would it be best
practice to pass and store a reference in each dependant or pass and
store the smart pointer?

I don't exactly understand what you mean by "only one manages its lifetime".
I know there is some tiny overhead with smart pointers, but the number
of objects that are going to use it is tremendous. It is used in
almost every class in my project, with possibly up to 5k or so
instances. I know one person's opinion at work was to just store a
reference while others passed the smart pointer around. What are your
thoughts?

First, we need to be clear on the rationale for using a shared_ptr in the
first place. From your first post:

I have a need to create a method that allocates something, but niether
the method or the class is responsible for managing its lifetime. I
feel like returning a raw pointer is a bad idea. So, I thought that I
could wrap it up in a smart poiner of some kind. However, the thing
that I am allocating is from a COM object, so I cannot just call
delete on it, instead if reuqires I call it's Release() method.

Usually, one would use auto_ptr for returning a pointer from a creation
function. One would do so to support exception safe coding. Unfortunately,
auto_ptr does not have a custom deleter. That is the reason to use
shared_ptr instead (come to think of it, unique_ptr is probably a better
choice!).

Now, with auto_ptr, one would release the pointer once the critical phase is
over. I would proceed similarly with shared_ptr or unique_ptr in this case.
In particular, I would not use shared_ptr members at all. The reason would
be that shared_ptr members would convey the message that the shared_ptr is
managing the lifetime and that "deletion upon loss of last reference" is
the ownership model used. If you have a different model (and that seems to
be the case), then your code should convey that; and therefore, shared_ptr
would be confusing.

If you use unique_ptr instead, the question would not even arise. I think,
you may want to have a look into unique_ptr.


That said: using reference members or pointer members can be very tricky. Be
sure to employ rigorous reasoning and testing to ensure that you don't leak
resources and that you don't access objects that died already. I find, that
encapsulating the ownership and lifetime management issues into smart
pointer classes can be very helpful. However, that smart pointer is not
very often shared_ptr.


Best

Kai-Uwe Bux
 
T

Thomas J. Gritzan

Kai-Uwe Bux said:
Christopher wrote:

[snip]
Is there any kind of pointer class in existance already there I can
customize its destruction to call the Release method on my allocated
object?
[snip]

Sure: both, tr1::shared_ptr and boost::shared_ptr allow for a custom
deleter. You pass the deleter as an argument upon construction of the
shared_ptr.

Since the OP asked about COM objects (which are those pseudo C++ classes
based on the interface IUnknown, widely used on Microsoft Windows), I
advice against using shared_ptr with them.

COM objects already carry a reference count, so an intrusive pointer
that can be adapted to the IUnknown interface would be a better idea.

Besides, the designers of COM forgot to protect the objects against
acidentally 'delete'ing them. Thus when wrapping a pointer in a
shared_ptr, an omitted custom deleter won't be captured at compile time.
 
C

Christopher

Usually, one would use auto_ptr for returning a pointer from a creation
function. One would do so to support exception safe coding. Unfortunately,
auto_ptr does not have a custom deleter. That is the reason to use
shared_ptr instead (come to think of it, unique_ptr is probably a better
choice!).

I looked up unique_ptr and it says:
"A unique_ptr is not CopyConstructible, nor CopyAssignable, however it
is MoveConstructible and Move-Assignable"

Ok no problem, but how do I move it? What do those terms
MoveConstructable and Move-Assignable mean?
How do I pass it around while being positive than it does not destroy
itself until I want it to do so?

If class A contains and manages the lifetime of the allocated object
class B provides a creation method that allocates the object
class A needs to contain the "master", but passes the allocated object
to its dependants for them to use
 
K

Kai-Uwe Bux

Christopher said:
I looked up unique_ptr and it says:
"A unique_ptr is not CopyConstructible, nor CopyAssignable, however it
is MoveConstructible and Move-Assignable"

Ok no problem, but how do I move it? What do those terms
MoveConstructable and Move-Assignable mean?
How do I pass it around while being positive than it does not destroy
itself until I want it to do so?

I have yet to learn C++0X, but I think these are concepts describing the
assignment operator and the constructor. So, you would move them using the
old syntax of

assignment
returning a value from a function
constructing an object from a source (but the source would be altered)

If class A contains and manages the lifetime of the allocated object
class B provides a creation method that allocates the object
class A needs to contain the "master", but passes the allocated object
to its dependants for them to use

Huh? That description is too high level for me. Can you illustrate that in
code? Also, what would be the question?


Best

Kai-Uwe Bux
 
C

Christopher

Huh? That description is too high level for me. Can you illustrate that in
code? Also, what would be the question?

Well I am tying to illistrate what the relationships I am dealing
with.
Quations - Is using a unique_ptr with a custom deallocater is the best
option here? (so far it looks that way, trying to be certain)
Whether and how to pass a reference without deallocating,
when using the unique_ptr, to dependant objects?

My real code would probably require more than a 1000 lines to
illistrate, so I will do my best to get the idea across in minimal
snippets. I doubt it is compilable. I can't think of a compilable
example to demonstrate what I am talking about, where it would make
sense.

-------------------------------
I've got a DisplayModeEnumerator class, which enumerates supported
display mode attributes for my DirectX specific application.
It has to retrieve a COM interface to a Direct3D device in order to
perform its duties as noted in the private method.
Since it keeps track of valid devices, and display mode attributes for
that device, and has to get an interface ot it anyway... I was
thinking it would be a good place to perform the duty of getting the
device in my project (make it a factory).


#ifndef DISPLAYMODEENUMERATOR_H
#define DISPLAYMODEENUMERATOR_H

// SNIP

// Windows Includes
#include <dxgi.h>

// Boost Includes
#include <boost/shared_ptr.hpp>

// SNIP

//------------------------------------------------------------------------------------------

// Enable boost::mem_fn for use of smart pointers with COM objects
#ifndef BOOST_MEM_FN_ENABLE_STDCALL
#define BOOST_MEM_FN_ENABLE_STDCALL
#endif

/**
* Shared pointer to a D3D10 device
*
* When creating this shared pointer, be sure to give it a custom
deallocater that calls the Release method of the device
* Syntax: ID3D10Device_SharedPtr(ID3D10Device, boost::mem_fn
(&ID3D10Device::Release));
*/
typedef boost::shared_ptr<ID3D10Device> ID3D10Device_SharedPtr;

//------------------------------------------------------------------------------------------
/**
* Display Mode Enumerator
*
* Queries the system for its display capabilites and provides an
interface to retrieve those capabilities
**/
class DisplayModeEnumerator
{
public:

/**
* Constructor
**/
DisplayModeEnumerator();

/**
* Deconstructor
**/
~DisplayModeEnumerator();


/**
* Gets the number of adapters
*
* @return unsigned - Number of supported adapters
**/
const unsigned GetNumAdapters() const;

// SNIP

private:


/**
* Creates a D3D device
*
* @param adapter - Adapter with which to create the device
*
* @return ID3D10Device_SharedPtr - boost_shared_ptr to a
ID3D10Device interface
**/
ID3D10Device_SharedPtr CreateDevice(IDXGIAdapter * adapter);

// SNIP
};

#endif // DISPLAYMODEENUMERATOR_H


---------------
I've got a GFXApplication class which the actual application can
derive from and serves as the manager and owner of all objects related
to rendering anything to the screen

#ifndef GFXAPPLICATION_H
#define GFXAPPLICATION_H

// EngineX Includes
#include "DisplayModeEnumerator.h"
#include "EffectManager.h"

// SNIP

//------------------------------------------------------------------------------------------
class GFXApplication
{
public:

/**
* Constructor
*/
GFXApplication(const std::string & title);

/**
* Deconstructor
*/
virtual ~GFXApplication();

/**
*
**/
void Init(HINSTANCE instance, const bool fullscreen, const unsigned
clientWidth, const unsigned clientHeight);

/**
* Starts the application run loop
*/
virtual int Run();

// SNIP

protected:

// SNIP

ID3D10Device * m_device; // D3D device
TextureManager * m_textureManager; // Contains all loaded textures
EffectManager * m_effectManager; // Contains all loaded effects

// SNIP
};

#endif


---------------
One example of a dependant is the EffectManager, which loads,
compiles, and manages "effects".
There are a plethora of classes like this one. A TexureManager, a
CameraManager, a ModelFactory, etc. All of which need access to the
device to perform thier duties. Note - Some people dislike the word
"Manager" in a class. I think we could safely replace it with factory.

#ifndef EFFECTMANAGER_H
#define EFFECTMANAGER_H

// EngineX Includes
// Not going to post these headers too, just including these for
illustration
#include "Graphics/Effects/Effect.h"
#include "Graphics/Textures/TextureManager.h"

// DirectX Includes
#include <d3dx10.h>
#include <d3d10.h>

// Standard Includes
#include <string>
#include <map>

//----------------------------------------------------------------------------
/**
* Manages the DirectX effects, which contain techniques for rendering
*/
class EffectManager
{
public:

/**
* Constructor
*
* @param device - an intialized Direct3D device to use
* @param effectsDirectory - Directory that contains the .fx
and .fxh files for the DirectX effects
*/
EffectManager(ID3D10Device & device, TextureManager &
textureManager, const std::string & effectDirectory);

/**
* Deconstructor
*/
~EffectManager();


/**
* Creates an effect from a file
*/
void CreateEffectFromFile(const std::string & effectName, const
std::string & filePath);

// SNIP

private:

ID3D10Device & m_device;
TextureManager & m_textureManager;

// SNIP

// Child effects
typedef std::map<std::string, Effect *> EffectMap;
EffectMap m_effects;
};

#endif // EFFECTMANAGER_H


-----

So, in this example code, the EffectManager and TextureManager are
members of the GFXApplication class. Both need a reference to the D3D
device for thier lifetime in order to perform thier duties. The
GFXApplication manages the lifetime of the D3D device. The
DisplayModeEnumerator creates the device and is called by the
GFXApplication.

So, I am wondering if I should keep passing references down the
hierarchy of classes.
I know lifetime management is an issue, but in this case it is fairly
easy - The device interface should not be released until the
application is ended.
 
K

Kai-Uwe Bux

Christopher said:
Well I am tying to illistrate what the relationships I am dealing
with.
Quations - Is using a unique_ptr with a custom deallocater is the best
option here? (so far it looks that way, trying to be certain)

I agree, it looks that way.

Whether and how to pass a reference without deallocating,
when using the unique_ptr, to dependant objects?

I would try:

unique_ptr<T> up ( new .... );
...
T & t_ref ( *up );

The documentation I saw for boost says that the expression *up has
unspecified type, but the latest draft of the standard says that the type
is

add_lvalue_reference<T>::type

which resolves to T& for object types.

My real code would probably require more than a 1000 lines to
illistrate, so I will do my best to get the idea across in minimal
snippets.

Thanks for the code (though I will snip it, I needed it to understand your
situation).

[snip]
*
* When creating this shared pointer, be sure to give it a custom
deallocater that calls the Release method of the device
* Syntax: ID3D10Device_SharedPtr(ID3D10Device, boost::mem_fn
(&ID3D10Device::Release));
*/
typedef boost::shared_ptr<ID3D10Device> ID3D10Device_SharedPtr;

(a) I think, that you would need to pass a second template argument.
(b) Does the Release() member function also deallocate the memory?
Otherwise, you might want to have a simple function

void dispose ( ID3D10Device * ptr ) {
ptr->Release();
delete ptr;
}

and pass &dispose to your smart pointer.

[snip]
class GFXApplication
protected:

// SNIP

ID3D10Device * m_device; // D3D device
TextureManager * m_textureManager; // Contains all loaded textures
EffectManager * m_effectManager; // Contains all loaded effects

// SNIP
}; [snip]
So, in this example code, the EffectManager and TextureManager are
members of the GFXApplication class. Both need a reference to the D3D
device for thier lifetime in order to perform thier duties. The
GFXApplication manages the lifetime of the D3D device. The
DisplayModeEnumerator creates the device and is called by the
GFXApplication.

I assume that the m_textureManager of a particular GFXApplication instance
will contain a reference to that instances *m_device. So, all dependent
objects can have synchronized lifetimes. In that case, I don't see what
would be wrong with references.


Best

Kai-Uwe Bux
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top