/* * * Copyright (C) 2012-2014, OFFIS e.V. * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation were developed by * * OFFIS e.V. * R&D Division Health * Escherweg 2 * D-26121 Oldenburg, Germany * * * Module: ofstd * * Author: Jan Schlamelcher * * Purpose: Implement fallback support for modern memory management * approaches (e.g. smart pointers) for older compilers. * */ #ifndef OFMEM_H #define OFMEM_H #include "dcmtk/config/osconfig.h" // make sure OS specific configuration is included first #include "dcmtk/ofstd/ofutil.h" // use native classes when c++11 is supported #ifdef DCMTK_USE_CXX11_STL #include template using OFshared_ptr = std::shared_ptr; template using OFunique_ptr = std::unique_ptr; #else //fallback implementations #if defined HAVE_SYNC_ADD_AND_FETCH && defined HAVE_SYNC_SUB_AND_FETCH #define OF_SHARED_PTR_COUNTER_TYPE size_t #elif defined HAVE_INTERLOCKED_INCREMENT && defined HAVE_INTERLOCKED_DECREMENT #if _MSC_VER <= 1200 #define OF_SHARED_PTR_COUNTER_TYPE LONG #else #define OF_SHARED_PTR_COUNTER_TYPE volatile LONG #endif #else #define OF_SHARED_PTR_COUNTER_TYPE size_t #define OF_SHARED_PTR_NEED_MUTEX 1 #include "dcmtk/ofstd/ofthread.h" #endif #ifdef HAVE_WINDOWS_H #define WIN32_LEAN_AND_MEAN #include #endif /** OFshared_ptr is a smart pointer that retains shared ownership of an object through a pointer. * Several OFshared_ptr objects may own the same object; the object is destroyed when the last remaining * OFshared_ptr referring to it is destroyed or reset. * * An OFshared_ptr may also own no objects, in which case it is called empty. * * OFshared_ptr meets the requirements of CopyConstructible and CopyAssignable. * @tparam T the type of the managed object, e.g. int for an OFshared_ptr behaving like an int*. * @note this implementation is meant to be a subset of the c++11's std::shared_ptr that lacks the * following features: swap support, support for weak references, atomic access to the managed object, * custom deleters and some functions like comparing OFshared_ptrs or read access * to the reference counter. * see http://en.cppreference.com/w/cpp/memory/shared_ptr to compare OFshared_ptr against std::shared_ptr. */ template class OFshared_ptr { public: /** Constructs a shared_ptr with pt as the managed object. * @param pt the managed object that this shared_ptr takes * the ownership to. */ OFshared_ptr( T* const pt = OFnullptr ) : m_pData( new Data( pt ) ) { } /** Constructs a shared_ptr which shares ownership of the object managed by other. * If other manages no object, *this manages no object too. * @param other another shared_ptr that this one will be copy constructed from. */ OFshared_ptr( const OFshared_ptr& other ) : m_pData( other.m_pData ) { m_pData->increment_count(); } /** Replaces the managed object with the one managed by other. * @param other another shared_ptr that this one will be copy assigned from. */ OFshared_ptr& operator=( const OFshared_ptr& other ) { if( this != &other ) { destroy(); m_pData = other.m_pData; m_pData->increment_count(); } return *this; } /** If *this owns an object and it is the last shared_ptr owning it, * the object is destroyed. Otherwise does nothing. */ ~OFshared_ptr() { destroy(); } /** Checks if *this manages an object, i.e. whether get() != 0. * @return OFTrue if *this manages an object, OFFalse otherwise. */ operator OFBool() const { return m_pData->pointer() != OFnullptr; } /** Checks if *this does not manage an object, i.e. whether get() == 0. * @return OFFalse if *this manages an object, OFTrue otherwise. */ OFBool operator!() const { return !m_pData->pointer(); } /** Dereferences pointer to the managed object. * @return a reference to the managed object. */ T& operator*() const { return *m_pData->pointer(); } /** Dereferences pointer to the managed object. * @return a pointer to the managed object. */ T* operator->() const { return m_pData->pointer(); } /** Returns a pointer to the managed object. * @return a pointer to the managed object. */ T* get() const { return m_pData->pointer(); } /** Replaces the managed object with an object pointed to by pt. * @param pt pointer to an object to acquire ownership of. */ void reset( T* const pt = OFnullptr ) { destroy(); m_pData = new Data( pt ); } private: /** Helper class containing the reference to the * managed object and the reference counter. */ class Data { public: /** Construct reference and counter from a raw pointer. * @param pt the raw pointer that becomes the managed object. */ Data( T* const pt ) : m_Count( 1 ) , m_pT( pt ) #ifdef OF_SHARED_PTR_NEED_MUTEX , m_Mutex() #endif { } /** Delete the managed object. * We are deleted only if the reference counter reached zero, * so we now have to delete the managed object. */ ~Data() { delete m_pT; } /** Increment the reference counter in a thread-safe and (if possible) * lock-free fashion. */ void increment_count() { #ifdef HAVE_SYNC_ADD_AND_FETCH __sync_add_and_fetch( &m_Count, 1 ); #elif defined HAVE_INTERLOCKED_INCREMENT InterlockedIncrement( &m_Count ); #else m_Mutex.lock(); ++m_Count; m_Mutex.unlock(); #endif } /** Decrement the reference counter in a thread-safe and (if possible) * lock-free fashion. * @return OFTrue if the reference counter reached zero, OFFalse otherwise. */ OFBool decrement_count() { #ifdef HAVE_SYNC_SUB_AND_FETCH return !__sync_sub_and_fetch( &m_Count, 1 ); #elif defined HAVE_INTERLOCKED_DECREMENT return !InterlockedDecrement( &m_Count ); #else m_Mutex.lock(); const OFBool result = !--m_Count; m_Mutex.unlock(); return result; #endif } /** Get the managed object. * @return a pointer to the managed object. */ T* pointer() const { return m_pT; } private: // Just to silence some warnings. Data(const Data&); Data& operator=(const Data&); /// The counter. OF_SHARED_PTR_COUNTER_TYPE m_Count; /// The pointer to the managed object. T* const m_pT; #ifdef OF_SHARED_PTR_NEED_MUTEX /// A mutex for platforms that don't support lock-free counters. OFMutex m_Mutex; #endif }; /** decrement the reference counter, destroy the managed * object and the counter if the counter reached zero. */ void destroy() { if( m_pData->decrement_count() ) delete m_pData; } /** A pointer to the management data structure containing the actual * reference to the managed object and the reference counter. */ Data* m_pData; }; /** OFunique_ptr is a smart pointer that retains sole ownership of an object through a pointer and destroys * that object when the unique_ptr goes out of scope. No two unique_ptr instances can manage the same object. * * The object is destroyed and its memory deallocated when either of the following happens: * - unique_ptr managing the object is destroyed * - unique_ptr managing the object is assigned another pointer via reset(). * * A unique_ptr may also own no objects, in which case it is called empty. * * OFunique_ptr is NOT CopyConstructible or CopyAssignable. * @tparam T the type of the managed object, e.g. int for an OFunique_ptr behaving like an int*. * @note this implementation is meant to be a subset of the c++11's std::unique_ptr that lacks the * following features: swap support, custom deleters, specialized handling of pointers to * arrays and some functions like comparing OFunique_ptrs or creating a hash key. * see http://en.cppreference.com/w/cpp/memory/unique_ptr to compare OFunique_ptr against std::unique_ptr. */ template class OFunique_ptr { public: /** typedef of pointer type T* for template programmers. */ typedef T* pointer; /** T, the type of the object managed by this unique_ptr. */ typedef T element_type; /** Constructs an empty OFunique_ptr */ OFunique_ptr() : m_pData( OFnullptr ) {} /** Constructs a OFunique_ptr which owns p. * @param p the pointer that's going to be owned by this unique_ptr. */ explicit OFunique_ptr( pointer p ) : m_pData( p ) {} /** Move constructor. * The move constructor moves the ownership of the managed * object from its parameter to the newly created OFunique_ptr * object, effectively emptying the former OFunique_ptr * object. * @param rhs an rvalue reference to another OFunique_ptr * object, e.g. obtained via OFmove. * @details *

Example

* This example shows how to move the ownership of a managed * object from one OFunique_ptr to another. Note that the * ownership always remains unique in this example, even * if an error occurred while reading the Dataset. * Therefore no memory leaks are possible! * @code * void consumeDataset( OFunique_ptr pDataset ) * . . . * OFunique_ptr pDataset( new DcmDataset ); * if( pDataset && pDataset->read( ... ).good() ) * { * // Error: copy constructor not available, as it would * // compromise the unique ownership principle * // consumeDataset( pDataset ); * * // OFmove allows us to 'tell' OFunique_ptr we want * // to give away the ownership. * consumeDataset( OFmove( pDataset ) ); * } * @endcode */ OFunique_ptr( OFrvalue_ref(OFunique_ptr) rhs ) #ifndef DOXYGEN : m_pData( rhs.m_pData ) { OFrvalue_access(rhs).m_pData = OFnullptr; } #else ; #endif /** Move assignment operator. * The move assignment operator moves the ownership of the * managed object from its parameter to itself, effectively emptying * the other OFunique_ptr object. See OFunique_ptr's move constructor * for more information. * @param rhs an rvalue reference to another OFunique_ptr * object, e.g. obtained via OFmove. */ OFunique_ptr& operator=( OFrvalue_ref(OFunique_ptr) rhs ) #ifndef DOXYGEN { OFunique_ptr& other = OFrvalue_access(rhs); if( &other != this ) { reset( other.m_pData ); other.m_pData = OFnullptr; } return *this; } #else ; #endif /** If get() == OFnullptr there are no effects -- otherwise, the owned object is destroyed. */ ~OFunique_ptr() { delete m_pData; } /** Replaces the managed object. The previously owned object is deleted if the unique_ptr * was not empty. * @param p the new pointer to be owned, defaults to OFnullptr. */ void reset( pointer p = OFnullptr ) { delete m_pData; m_pData = p; } /** Releases the ownership of the managed object if any. * Retrieves the owned object (if any) and lets the unique_ptr become empty. * @return same as get(). */ pointer release() { pointer const p = m_pData; m_pData = OFnullptr; return p; } /** Returns a pointer to the managed object or OFnullptr if no object is owned. * @return Pointer to the managed object or OFnullptr if no object is owned. */ pointer get() const { return m_pData; } /** Checks whether *this owns an object, i.e. whether get() != OFnullptr. * @return get() != OFnullptr. */ operator bool() const { return m_pData != OFnullptr; } /** Checks whether *this does NOT own an object, i.e. whether get() == OFnullptr. * @return get() == OFnullptr. */ bool operator!() const { return m_pData == OFnullptr; } /** Access the object owned by *this. * @return the object owned by *this, i.e. *get(). */ T& operator*() const { return *m_pData; } /** Access the object owned by *this. * @return same as get(). */ pointer operator->() const { return m_pData; } private: /// Disable copy construction. OFunique_ptr(const OFunique_ptr&); /// Disable copy assignment. OFunique_ptr& operator=(const OFunique_ptr&); /// The underlying (raw) pointer. pointer m_pData; }; #endif //c++11 #endif //OFMEM_H