Re: smart pointer with custom deconstruction?
On Feb 28, 1:45 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
Christopher wrote:
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 i=
n
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.