c++-gtk-utils
Public Member Functions | Friends
Cgu::SharedLockPtr< T > Class Template Reference

This is a smart pointer for managing the lifetime of objects allocated on freestore, with a thread safe reference count. More...

#include <c++-gtk-utils/shared_ptr.h>

List of all members.

Public Member Functions

 SharedLockPtr (T *ptr=0)
 SharedLockPtr (T *ptr, Cgu::SharedPtrAllocFail::Leave tag)
void reset (T *ptr=0)
void reset (T *ptr, Cgu::SharedPtrAllocFail::Leave tag)
 SharedLockPtr (const SharedLockPtr &sh_ptr)
 SharedLockPtr (SharedLockPtr &&sh_ptr)
template<class U >
 SharedLockPtr (const SharedLockPtr< U > &sh_ptr)
template<class U >
 SharedLockPtr (SharedLockPtr< U > &&sh_ptr)
SharedLockPtroperator= (SharedLockPtr sh_ptr)
template<class U >
SharedLockPtroperator= (const SharedLockPtr< U > &sh_ptr)
template<class U >
SharedLockPtroperator= (SharedLockPtr< U > &&sh_ptr)
T * get () const
T & operator* () const
T * operator-> () const
unsigned int get_refcount () const
 ~SharedLockPtr ()

Friends

class SharedLockPtr

Detailed Description

template<class T>
class Cgu::SharedLockPtr< T >

This is a smart pointer for managing the lifetime of objects allocated on freestore, with a thread safe reference count.

See also:
SharedPtr SharedPtrError

Class SharedLockPtr is a version of the shared pointer class which includes locking so that it can be accessed in multiple threads (although the word Lock is in the title, by default it uses glib atomic functions to access the reference count rather than a mutex, so the overhead should be very small). Note that only the reference count is protected, so this is thread safe in the sense in which a raw pointer is thread safe. A shared pointer accessed in one thread referencing a particular object is thread safe as against another shared pointer accessing the same object in a different thread. It is thus suitable for use in different Std C++ containers which exist in different threads but which contain shared objects by reference. But:

  1. If the referenced object is to be modified in one thread and read or modified in another thread an appropriate mutex for the referenced object is required (unless that referenced object does its own locking).
  1. If the same instance of shared pointer is to be modified in one thread (by assigning to the pointer so that it references a different object, or by moving from it), and copied (assigned from or used as the argument of a copy constructor), accessed, destroyed or modified in another thread, a mutex for that instance of shared pointer is required.
  1. Objects referenced by shared pointers which are objects for which POSIX provides no guarantees (in the main, those which are not built-in types), such as strings and similar containers, may not support concurrent reads in different threads. That depends on the library implementation concerned. If that is the case, a mutex for the referenced object will also be required when reading any given instance of such an object in more than one thread by dereferencing any shared pointers referencing it (and indeed, when not using shared pointers at all).

As mentioned, by default glib atomic functions are used to provide thread-safe manipulation of the reference count. However, a library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX before shared_ptr.h is parsed so as to use mutexes instead, which might be useful for some debugging purposes.

Comparison with std::shared_ptr

Most of the things that can be done by this class can be done by using std::shared_ptr in C++11, but this class is retained in the c++-gtk-utils library not only to retain compatibility with series 1.2 of the library, but also to cater for some cases not met (or not so easily met) by std::shared_ptr:

(i) Glib memory slices provide an efficient small object allocator (they are likely to be significantly more efficient than global operator new()/new[](), which generally hand off to malloc(), and whilst malloc() is good for large block allocations it is generally poor as a small object allocator). Internal Cgu::SharedLockPtr allocation using glib memory slices can be achieved by compiling the library with the –with-glib-memory-slices-no-compat configuration option.

(ii) If glib memory slices are not used (which do not throw), constructing a shared pointer for a new managed object (or calling reset() for a new managed object) might throw if internal allocation fails. Although by default the Cgu::SharedLockPtr implementation will delete the new managed object in such a case, it also provides an alternative constructor and reset() method which instead enable the new object to be accessed via the thrown exception object so that user code can decide what to do; std::shared_ptr deletes the new object in every case.

(iii) A user can explicitly state whether the shared pointer object is to have atomic increment and decrement-and-test with respect to the reference count so that the reference count is thread safe ('no' in the case of Cgu::SharedPtr, and 'yes' in the case of Cgu::SharedLockPtr). Using atomic functions is unnecessary if the managed object concerned is only addressed in one thread (and might cause unwanted cache flushing in certain circumstances). std::shared_ptr will generally always use atomic functions with respect to its reference count in a multi-threaded program.

In favour of C++11's std::shared_ptr, it has an associated std::make_shared() factory function which will construct both the referenced object and the shared pointer's reference count within a single memory block when the first shared pointer managing a particular object is constructed. Cgu::SharedPtr and Cgu::SharedLockPtr always allocate these separately, but this is partly mitigated by the use of glib memory slices to allocate the reference count where the –with-glib-memory-slices-no-compat configuration option is chosen.

In addition, std::shared_ptr has an associated std::weak_ptr class, which Cgu::SharedLockPtr does not (there is a Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle and is only usable with GObjects), and shared_ptr objects also have some atomic store, load and exchange functions provided for them which enable concurrent modifications of the same instance of shared_ptr in different threads to have defined results.


Constructor & Destructor Documentation

template<class T>
Cgu::SharedLockPtr< T >::SharedLockPtr ( T *  ptr = 0)
inlineexplicit

Constructor taking an unmanaged object.

Parameters:
ptrThe object which the SharedLockPtr is to manage (if any).
Exceptions:
std::bad_allocThis constructor will not throw if the 'ptr' argument has a NULL value (the default), otherwise it might throw std::bad_alloc if memory is exhausted and the system throws in that case. If such an exception is thrown, this constructor is exception safe (it does not leak resources), but as well as cleaning itself up this constructor will also delete the managed object passed to it to avoid a memory leak. If such automatic deletion is not wanted in that case, use the version of this constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument.
Note:
1. std::bad_alloc will not be thrown if the library has been installed using the –with-glib-memory-slices-no-compat configuration option: instead glib will terminate the program if it is unable to obtain memory from the operating system.
2. By default, glib atomic functions are used to provide thread-safe manipulation of the reference count. However, a library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX before shared_ptr.h is parsed so as to use mutexes instead, which might be useful for some debugging purposes. Were she to do so, Cgu::Thread::MutexError might be thrown by this constructor if initialization of the mutex fails, but it is usually not worth checking for this.
template<class T>
Cgu::SharedLockPtr< T >::SharedLockPtr ( T *  ptr,
Cgu::SharedPtrAllocFail::Leave  tag 
)
inline

Constructor taking an unmanaged object.

Parameters:
ptrThe object which the SharedLockPtr is to manage.
tagPassing the tag emumerator Cgu::SharedPtrAllocFail::leave causes this constructor not to delete the new managed object passed as the 'ptr' argument in the event of internal allocation in this method failing because of memory exhaustion (in that event, Cgu::SharedPtrError will be thrown).
Exceptions:
Cgu::SharedPtrErrorThis constructor might throw Cgu::SharedPtrError if memory is exhausted and the system would otherwise throw std::bad_alloc in that case. This constructor is exception safe (it does not leak resources), and if such an exception is thrown it will clean itself up, but it will not attempt to delete the new managed object passed to it. Access to the object passed to the 'ptr' argument can be obtained via the thrown Cgu::SharedPtrError object.
Note:
1. On systems with over-commit/lazy-commit combined with virtual memory (swap), it is rarely useful to check for memory exhaustion, so in those cases this version of the constructor will not be useful.
2. If the library has been installed using the –with-glib-memory-slices-no-compat configuration option this version of the constructor will also not be useful: instead glib will terminate the program if it is unable to obtain memory from the operating system.
3. By default, glib atomic functions are used to provide thread-safe manipulation of the reference count. However, a library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX before shared_ptr.h is parsed so as to use mutexes instead, which might be useful for some debugging purposes. Were she to do so, Cgu::SharedPtrError might be thrown by this constructor if initialization of the mutex fails (even if the –with-glib-memory-slices-no-compat configuration option is chosen), but it is usually not worth checking for such mutex initialization failure.
template<class T>
Cgu::SharedLockPtr< T >::SharedLockPtr ( const SharedLockPtr< T > &  sh_ptr)
inline

This copy constructor does not throw.

Parameters:
sh_ptrThe shared pointer to be copied.
template<class T>
Cgu::SharedLockPtr< T >::SharedLockPtr ( SharedLockPtr< T > &&  sh_ptr)
inline

The move constructor does not throw. It has move semantics.

Parameters:
sh_ptrThe shared pointer to be moved.
template<class T>
template<class U >
Cgu::SharedLockPtr< T >::SharedLockPtr ( const SharedLockPtr< U > &  sh_ptr)
inline

A version of the copy constructor which enables pointer type conversion (assuming the type passed is implicitly type convertible to the managed type, such as a derived type). This copy constructor does not throw.

Parameters:
sh_ptrThe shared pointer to be copied.
template<class T>
template<class U >
Cgu::SharedLockPtr< T >::SharedLockPtr ( SharedLockPtr< U > &&  sh_ptr)
inline

A version of the move constructor which enables pointer type conversion (assuming the type passed is implicitly type convertible to the managed type, such as a derived type). This move constructor does not throw.

Parameters:
sh_ptrThe shared pointer to be moved.
template<class T>
Cgu::SharedLockPtr< T >::~SharedLockPtr ( )
inline

The destructor does not throw unless the destructor of a managed object throws - that should never happen.


Member Function Documentation

template<class T>
T* Cgu::SharedLockPtr< T >::get ( ) const
inline

This method does not throw.

Returns:
A pointer to the managed object (or NULL if none is managed).
template<class T>
unsigned int Cgu::SharedLockPtr< T >::get_refcount ( ) const
inline

This method does not throw.

Returns:
The number of SharedLockPtr objects referencing the managed object (or 0 if none is managed by this SharedLockPtr).
Note:
The return value may not be valid if another thread has changed the reference count before the value returned by this method is acted on. It is provided as a utility, but may not be meaningful, depending on the intended usage.
template<class T>
T& Cgu::SharedLockPtr< T >::operator* ( ) const
inline

This method does not throw.

Returns:
A reference to the managed object.
template<class T>
T* Cgu::SharedLockPtr< T >::operator-> ( ) const
inline

This method does not throw.

Returns:
A pointer to the managed object (or NULL if none is managed).
template<class T>
SharedLockPtr& Cgu::SharedLockPtr< T >::operator= ( SharedLockPtr< T >  sh_ptr)
inline

This method (and so copy or move assignment) does not throw unless the destructor of a managed object throws.

Parameters:
sh_ptrthe assignor.
Returns:
The SharedLockPtr object after assignment.
template<class T>
template<class U >
SharedLockPtr& Cgu::SharedLockPtr< T >::operator= ( const SharedLockPtr< U > &  sh_ptr)
inline

A version of the assignment operator which enables pointer type conversion (assuming the type passed is implicitly type convertible to the managed type, such as a derived type). This method does not throw unless the destructor of a managed object throws.

Parameters:
sh_ptrthe assignor.
Returns:
The SharedLockPtr object after assignment.
template<class T>
template<class U >
SharedLockPtr& Cgu::SharedLockPtr< T >::operator= ( SharedLockPtr< U > &&  sh_ptr)
inline

A version of the operator for move assignment which enables pointer type conversion (assuming the type passed is implicitly type convertible to the managed type, such as a derived type). This method does not throw unless the destructor of a managed object throws.

Parameters:
sh_ptrthe shared pointer to be moved.
Returns:
The SharedLockPtr object after the move operation.
template<class T>
void Cgu::SharedLockPtr< T >::reset ( T *  ptr = 0)
inline

Causes the SharedLockPtr to cease to manage its managed object (if any), deleting it if this is the last SharedLockPtr object managing it. If the argument passed is not NULL, the SharedLockPtr object will manage the new object passed (which must not be managed by any other SharedLockPtr object). This method is exception safe, but see the comments below on std::bad_alloc.

Parameters:
ptrNULL (the default), or a new unmanaged object to manage.
Exceptions:
std::bad_allocThis method will not throw if the 'ptr' argument has a NULL value (the default) and the destructor of a managed object does not throw, otherwise it might throw std::bad_alloc if memory is exhausted and the system throws in that case. Note that if such an exception is thrown then this method will do nothing (it is strongly exception safe and will continue to manage the object it was managing prior to the call), except that it will delete the new managed object passed to it to avoid a memory leak. If such automatic deletion in the event of such an exception is not wanted, use the reset() method taking a Cgu::SharedPtrAllocFail::Leave tag type as its second argument.
Note:
1. std::bad_alloc will not be thrown if the library has been installed using the –with-glib-memory-slices-no-compat configuration option: instead glib will terminate the program if it is unable to obtain memory from the operating system.
2. By default, glib atomic functions are used to provide thread-safe manipulation of the reference count. However, a library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX before shared_ptr.h is parsed so as to use mutexes instead, which might be useful for some debugging purposes. Were she to do so, Cgu::Thread::MutexError might be thrown by this method if initialization of the mutex fails, but it is usually not worth checking for this.
3. A SharedLockPtr object protects its reference count but not the managed object or its other internals. The reset() method should not be called by one thread in respect of a particular SharedLockPtr object while another thread may be operating on, copying or dereferencing the same instance of SharedLockPtr. It is thread-safe as against another instance of SharedLockPtr managing the same object.
template<class T>
void Cgu::SharedLockPtr< T >::reset ( T *  ptr,
Cgu::SharedPtrAllocFail::Leave  tag 
)
inline

Causes the SharedLockPtr to cease to manage its managed object (if any), deleting it if this is the last SharedLockPtr object managing it. The SharedLockPtr object will manage the new object passed (which must not be managed by any other SharedLockPtr object). This method is exception safe, but see the comments below on Cgu::SharedPtrError.

Parameters:
ptrA new unmanaged object to manage (if no new object is to be managed, use the version of reset() taking a default value of NULL).
tagPassing the tag emumerator Cgu::SharedPtrAllocFail::leave causes this method not to delete the new managed object passed as the 'ptr' argument in the event of internal allocation in this method failing because of memory exhaustion (in that event, Cgu::SharedPtrError will be thrown).
Exceptions:
Cgu::SharedPtrErrorThis method might throw Cgu::SharedPtrError if memory is exhausted and the system would otherwise throw std::bad_alloc in that case. Note that if such an exception is thrown then this method will do nothing (it is strongly exception safe and will continue to manage the object it was managing prior to the call), and it will not attempt to delete the new managed object passed to it. Access to the object passed to the 'ptr' argument can be obtained via the thrown Cgu::SharedPtrError object.
Note:
1. A SharedLockPtr object protects its reference count but not the managed object or its other internals. The reset() method should not be called by one thread in respect of a particular SharedLockPtr object while another thread may be operating on, copying or dereferencing the same instance of SharedLockPtr. It is thread-safe as against another instance of SharedLockPtr managing the same object.
2. On systems with over-commit/lazy-commit combined with virtual memory (swap), it is rarely useful to check for memory exhaustion, so in those cases this version of the reset() method will not be useful.
3. If the library has been installed using the –with-glib-memory-slices-no-compat configuration option this version of the reset() method will also not be useful: instead glib will terminate the program if it is unable to obtain memory from the operating system.
4. By default, glib atomic functions are used to provide thread-safe manipulation of the reference count. However, a library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX before shared_ptr.h is parsed so as to use mutexes instead, which might be useful for some debugging purposes. Were she to do so, Cgu::SharedPtrError might be thrown by this method if initialization of the mutex fails (even if the –with-glib-memory-slices-no-compat configuration option is chosen), but it is usually not worth checking for such mutex initialization failure.

Friends And Related Function Documentation

template<class T>
friend class SharedLockPtr
friend

The documentation for this class was generated from the following file: