7.2 Handle

A Handle is basically a container to store a pointer to some data and a user counter. The user counter counts how many handles point to the same memory area. This allows the memory area to be cleanly destroyed when the last handle pointing to it is destroyed (last one to leave the room shuts off light).

The Handle class was implemented concurrency resistent. It can be used in multi-threaded code without special care. The usage counter for example is allocated in global memory (not on the current stack), thus the handle can be used to share data among threads with a safe deallocation strategy: the last user deletes the data pointer. Moreover this user counter is an atomic counter (see Section 7.1), which is thread safe since all operations are performed atomically.

Handle needs a pointer to some memory area in its constructor. The easiest way to construct a handle is as follows:
Handle<HDT> handle (new HDT);
Thus the data pointer is created during the construction of the handle. It is however possible to create the data pointer outside the handle construction, but code gets often hard to read because of asymetric new-delete pairs.


Synopsis


  #include <lyric/Handle.hpp>
  
  template <class HDT>
  class Handle
  {
  public:
    ~Handle ();
    Handle (HDT* data);
    Handle (const Handle& handle);
    Handle& operator = (const Handle& handle);
    HDT* operator -> ();
    HDT* operator -> () const;
    HDT* dataptr () const;
  };


Description


˜Handle ()
Destroys this handle, releasing resources as needed. If the data area pointer stored in this handle is the last to point on the location, this data area is returned to the system. The delete operator is applied on the data pointer.

Handle (HDT* data)
Constructs this handle to be a pointer on the memory area given by data. The data area usage counter is set to one.
The safest is to allocate the data area directly in the construction of this handle with:
Handle<HDT> handle (new HDT);

Handle (const Handle& handle)
Constructs this handle by cloning the given handle. At the end this handle stores the pointer to the same data area as the given handle, and the users count is increased (this handle and handle point to the same memory area, sharing it).

Handle& operator = (const Handle& handle)
Assigns handle to this handle, and returns a reference to this handle for assignment chaining. Before the assignation this handle’s users count is decreased and if this handle was the last user of the data area, the later is properly destroyed. The the actuall assignment, cloning handle into this handle takes place. At the end this handle stores the pointer to the same data area as the given handle, and the users count is increased (this handle and handle point to the same memory area, sharing it).

HDT* operator -> ()
Returns the pointer to the data area pointed to by this handle. If HDT is a class or structure, all public members are accessible through the -> operator as if this handle was a pointer to the structure or class.

HDT* operator -> () const
Returns the pointer to the data area pointed to by this handle. If HDT is a class or structure, all public members are accessible through the -> operator as if this handle was a pointer to the structure or class.

HDT* dataptr () const
Returns the pointer to the data area pointed to by this handle. This gives direct access to the data pointed by the address stored in this handle.