//----------------------------------------------------------------------------- // Project : SDK Core // // Category : SDK Core Interfaces // Filename : pluginterfaces/base/smartpointer.h // Created by : Steinberg, 01/2004 // Description : Basic Interface // //----------------------------------------------------------------------------- // This file is part of a Steinberg SDK. It is subject to the license terms // in the LICENSE file found in the top-level directory of this distribution // and at www.steinberg.net/sdklicenses. // No part of the SDK, including this file, may be copied, modified, propagated, // or distributed except according to the terms contained in the LICENSE file. //----------------------------------------------------------------------------- #pragma once #include "pluginterfaces/base/fplatform.h" #if SMTG_CPP11_STDLIBSUPPORT #include #endif //------------------------------------------------------------------------ namespace Steinberg { //------------------------------------------------------------------------ // IPtr //------------------------------------------------------------------------ /** IPtr - Smart pointer template class. \ingroup pluginBase - can be used as an I* pointer - handles refCount of the interface - Usage example: \code IPtr path (sharedPath); if (path) path->ascend (); \endcode */ template class IPtr { public: //------------------------------------------------------------------------ inline IPtr (I* ptr, bool addRef = true); inline IPtr (const IPtr&); template inline IPtr (const IPtr& other) : ptr (other.get ()) { if (ptr) ptr->addRef (); } inline IPtr (); inline ~IPtr (); inline I* operator= (I* ptr); inline IPtr& operator= (const IPtr& other); template inline IPtr& operator= (const IPtr& other) { operator= (other.get ()); return *this; } inline operator I* () const { return ptr; } // act as I* inline I* operator-> () const { return ptr; } // act as I* inline I* get () const { return ptr; } #if SMTG_CPP11_STDLIBSUPPORT inline IPtr (IPtr&& movePtr) SMTG_NOEXCEPT : ptr (movePtr.take ()) { } template inline IPtr (IPtr&& movePtr) SMTG_NOEXCEPT : ptr (movePtr.take ()) { } inline IPtr& operator= (IPtr&& movePtr) SMTG_NOEXCEPT { if (ptr) ptr->release (); ptr = movePtr.take (); return *this; } template inline IPtr& operator= (IPtr&& movePtr) { if (ptr) ptr->release (); ptr = movePtr.take (); return *this; } #endif inline void reset (I* obj = nullptr) { if (ptr) ptr->release(); ptr = obj; } I* take () SMTG_NOEXCEPT { I* out = ptr; ptr = nullptr; return out; } template static IPtr adopt (T* obj) SMTG_NOEXCEPT { return IPtr (obj, false); } //------------------------------------------------------------------------ protected: I* ptr; }; //------------------------------------------------------------------------ template inline IPtr::IPtr (I* _ptr, bool addRef) : ptr (_ptr) { if (ptr && addRef) ptr->addRef (); } //------------------------------------------------------------------------ template inline IPtr::IPtr (const IPtr& other) : ptr (other.ptr) { if (ptr) ptr->addRef (); } //------------------------------------------------------------------------ template inline IPtr::IPtr () : ptr (0) { } //------------------------------------------------------------------------ template inline IPtr::~IPtr () { if (ptr) { ptr->release (); ptr = nullptr; //TODO_CORE: how much does this cost? is this something hiding for us? } } //------------------------------------------------------------------------ template inline I* IPtr::operator= (I* _ptr) { if (_ptr != ptr) { if (ptr) ptr->release (); ptr = _ptr; if (ptr) ptr->addRef (); } return ptr; } //------------------------------------------------------------------------ template inline IPtr& IPtr::operator= (const IPtr& _ptr) { operator= (_ptr.ptr); return *this; } //------------------------------------------------------------------------ /** OPtr - "owning" smart pointer used for newly created FObjects. \ingroup pluginBase FUnknown implementations are supposed to have a refCount of 1 right after creation. So using an IPtr on newly created objects would lead to a leak. Instead the OPtr can be used in this case. \n Example: \code OPtr path = FHostCreate (IPath, hostClasses); // no release is needed... \endcode The assignment operator takes ownership of a new object and releases the old. So its safe to write: \code OPtr path = FHostCreate (IPath, hostClasses); path = FHostCreate (IPath, hostClasses); path = 0; \endcode This is the difference to using an IPtr with addRef=false. \code // DONT DO THIS: IPtr path (FHostCreate (IPath, hostClasses), false); path = FHostCreate (IPath, hostClasses); path = 0; \endcode This will lead to a leak! */ template class OPtr : public IPtr { public: //------------------------------------------------------------------------ inline OPtr (I* p) : IPtr (p, false) {} inline OPtr (const IPtr& p) : IPtr (p) {} inline OPtr (const OPtr& p) : IPtr (p) {} inline OPtr () {} inline I* operator= (I* _ptr) { if (_ptr != this->ptr) { if (this->ptr) this->ptr->release (); this->ptr = _ptr; } return this->ptr; } }; //------------------------------------------------------------------------ /** Assigning newly created object to an IPtr. Example: \code IPtr path = owned (FHostCreate (IPath, hostClasses)); \endcode which is a slightly shorter form of writing: \code IPtr path = OPtr (FHostCreate (IPath, hostClasses)); \endcode */ template IPtr owned (I* p) { return IPtr (p, false); } /** Assigning shared object to an IPtr. Example: \code IPtr path = shared (iface.getXY ()); \endcode */ template IPtr shared (I* p) { return IPtr (p, true); } #if SMTG_CPP11_STDLIBSUPPORT //------------------------------------------------------------------------ // Ownership functionality //------------------------------------------------------------------------ namespace SKI { namespace Detail { struct Adopt; } // Detail /** Strong typedef for shared reference counted objects. * Use SKI::adopt to unwrap the provided object. * @tparam T Referenced counted type. */ template class Shared { friend struct Detail::Adopt; T* obj = nullptr; }; /** Strong typedef for transferring the ownership of reference counted objects. * Use SKI::adopt to unwrap the provided object. * After calling adopt the reference in this object is null. * @tparam T Referenced counted type. */ template class Owned { friend struct Detail::Adopt; T* obj = nullptr; }; /** Strong typedef for using reference counted objects. * Use SKI::adopt to unwrap the provided object. * After calling adopt the reference in this object is null. * @tparam T Referenced counted type. */ template class Used { friend struct Detail::Adopt; T* obj = nullptr; }; namespace Detail { struct Adopt { template static IPtr adopt (Shared& ref) { using Steinberg::shared; return shared (ref.obj); } template static IPtr adopt (Owned& ref) { using Steinberg::owned; IPtr out = owned (ref.obj); ref.obj = nullptr; return out; } template static T* adopt (Used& ref) { return ref.obj; } template