smart pointer with custom deconstruction?

Discussion in 'C++' started by Christopher, Feb 27, 2009.

  1. Christopher

    Christopher Guest

    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.
    Christopher, Feb 27, 2009
    #1
    1. Advertising

  2. Christopher

    Kai-Uwe Bux Guest

    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
    Kai-Uwe Bux, Feb 27, 2009
    #2
    1. Advertising

  3. Christopher

    Christopher Guest

    On Feb 27, 3:51 pm, Kai-Uwe Bux <> wrote:
    > 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!
    Christopher, Feb 27, 2009
    #3
  4. Christopher schrieb:
    > 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.

    --
    Thomas
    Thomas J. Gritzan, Feb 28, 2009
    #4
  5. Christopher

    Kai-Uwe Bux Guest

    Christopher wrote:

    > On Feb 27, 3:51 pm, Kai-Uwe Bux <> wrote:
    >> 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
    Kai-Uwe Bux, Feb 28, 2009
    #5
  6. Kai-Uwe Bux schrieb:
    > 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.

    --
    Thomas
    Thomas J. Gritzan, Feb 28, 2009
    #6
  7. Christopher

    Christopher Guest

    On Feb 27, 3:51 pm, Kai-Uwe Bux <> wrote:
    > 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
    Christopher, Feb 28, 2009
    #7
  8. Christopher

    Kai-Uwe Bux Guest

    Christopher wrote:

    > On Feb 27, 3:51 pm, Kai-Uwe Bux <> wrote:
    >> 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?


    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
    Kai-Uwe Bux, Feb 28, 2009
    #8
  9. Christopher

    Christopher Guest

    On Feb 28, 1:45 am, Kai-Uwe Bux <> 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 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.
    Christopher, Feb 28, 2009
    #9
  10. Christopher

    Kai-Uwe Bux Guest

    Christopher wrote:

    > On Feb 28, 1:45 am, Kai-Uwe Bux <> 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
    >> 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)


    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
    Kai-Uwe Bux, Feb 28, 2009
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. coala
    Replies:
    3
    Views:
    370
    coala
    Sep 6, 2006
  2. coala
    Replies:
    1
    Views:
    587
    Victor Bazarov
    Sep 6, 2006
  3. Hicham Mouline
    Replies:
    100
    Views:
    2,072
    Noah Roberts
    Aug 25, 2009
  4. sickfaichezi
    Replies:
    2
    Views:
    105
    David Balmain
    Sep 22, 2006
  5. Replies:
    8
    Views:
    110
    Tad J McClellan
    Sep 9, 2008
Loading...

Share This Page