diff --git a/Modules/Core/include/mitkWeakPointer.h b/Modules/Core/include/mitkWeakPointer.h index ba13d6a7d7..3775eec39c 100644 --- a/Modules/Core/include/mitkWeakPointer.h +++ b/Modules/Core/include/mitkWeakPointer.h @@ -1,189 +1,323 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef __mitkWeakPointer_h -#define __mitkWeakPointer_h +#ifndef mitkWeakPointer_h +#define mitkWeakPointer_h -#include "mitkMessage.h" -#include - -#include #include +#include namespace mitk { - /** \class WeakPointer - * \brief Implements a weak reference to an object. - * - * Extends the standard itk WeakPointer by listening to delete events of itk::Objects. - * When an itk::Object is deleted the WeakPointer sets its internal Pointer to 0. - * This enables checking against 0 and avoids crashes by accessing changed memory. - * Furthermore it dispatches Modified events with the mitkMessageDelegate system which is - * much easier to use. - */ - template - class WeakPointer + template + class WeakPointer final { public: - /** Extract infoirmation from template parameter. */ - typedef TObjectType ObjectType; + WeakPointer() noexcept + : m_RawPointer(nullptr) + { + } + + WeakPointer(T *rawPointer) + : m_RawPointer(rawPointer) + { + this->AddDeleteEventObserver(); + } - typedef Message1 itkObjectEvent; - //##Documentation - //## @brief AddEvent is emitted when the object pointed to gets deleted - itkObjectEvent ObjectDelete; + WeakPointer(const WeakPointer &other) + : m_RawPointer(other.m_RawPointer) + { + this->AddDeleteEventObserver(); + } - //##Documentation - //## @brief AddEvent is emitted when the object pointed to gets modified - itkObjectEvent ObjectModified; + // Because the observed object is keeping references to its observers, + // move semantics can't be implemented more effective than its alternative + // to simply copy and destruct. It would still be necessary to remove the + // old observer and to add the new one. + WeakPointer(WeakPointer &&) = delete; + WeakPointer & operator =(WeakPointer &&) = delete; - /** Constructor. */ - WeakPointer() : m_DeleteObserverTag(-1), m_ModifiedObserverTag(-1), m_Pointer(nullptr) {} - /** Copy constructor. */ - WeakPointer(const WeakPointer &p) - : m_DeleteObserverTag(-1), m_ModifiedObserverTag(-1), m_Pointer(p.m_Pointer) + ~WeakPointer() noexcept { - this->AddDeleteAndModifiedObserver(); + try + { + this->RemoveDeleteEventObserver(); + } + catch (...) + { + // Swallow. Otherwise, the application would terminate if another + // exception is already propagating. + } } - /** Constructor to pointer p. */ - WeakPointer(ObjectType *p) : m_DeleteObserverTag(-1), m_ModifiedObserverTag(-1), m_Pointer(p) + // Prefer classic implementation to copy-and-swap idiom. Swapping is + // non-trivial for this class as the observed object is keeping references + // to its observers. + WeakPointer & operator =(const WeakPointer &other) { - this->AddDeleteAndModifiedObserver(); + if (this != &other) + { + this->RemoveDeleteEventObserver(); + + // m_RawPointer is guaranteed not to be nullptr as nullptr assignment + // is handled in a separate implementation of the assignment operator. + m_RawPointer = other.m_RawPointer; + this->AddDeleteEventObserver(); + } + + return *this; } - /** Destructor. */ - ~WeakPointer() + WeakPointer & operator =(std::nullptr_t) { - this->RemoveDeleteAndModifiedObserver(); + this->RemoveDeleteEventObserver(); + m_RawPointer = nullptr; - m_Pointer = nullptr; + return *this; } - /** Overload operator ->. */ - ObjectType *operator->() const { return m_Pointer; } - /** Return pointer to object. */ - operator ObjectType *() const { return m_Pointer; } - /** Template comparison operators. */ - template - bool operator==(R r) const + explicit operator bool() const noexcept { - return (m_Pointer == (ObjectType *)r); + return nullptr != m_RawPointer; } - template - bool operator!=(R r) const + + bool IsExpired() const noexcept { - return (m_Pointer != (ObjectType *)r); + return !*this; } - /** Access function to pointer. */ - ObjectType *GetPointer() const { return m_Pointer; } - /** Comparison of pointers. Less than comparison. */ - bool operator<(const WeakPointer &r) const { return (void *)m_Pointer < (void *)r.m_Pointer; } - /** Comparison of pointers. Greater than comparison. */ - bool operator>(const WeakPointer &r) const { return (void *)m_Pointer > (void *)r.m_Pointer; } - /** Comparison of pointers. Less than or equal to comparison. */ - bool operator<=(const WeakPointer &r) const { return (void *)m_Pointer <= (void *)r.m_Pointer; } - /** Comparison of pointers. Greater than or equal to comparison. */ - bool operator>=(const WeakPointer &r) const { return (void *)m_Pointer >= (void *)r.m_Pointer; } - /** Test if the pointer has been initialized */ - bool IsNotNull() const { return m_Pointer != nullptr; } - bool IsNull() const { return m_Pointer == nullptr; } - /** Overload operator assignment. */ - WeakPointer &operator=(const WeakPointer &r) { return this->operator=(r.GetPointer()); } - /** Overload operator assignment. */ - WeakPointer &operator=(ObjectType *r) + typename T::Pointer Lock() const noexcept { - this->RemoveDeleteAndModifiedObserver(); - m_Pointer = r; - this->AddDeleteAndModifiedObserver(); - return *this; + return m_RawPointer; } - /** Function to print object pointed to. */ - ObjectType *Print(std::ostream &os) const + private: + void AddDeleteEventObserver() { - // This prints the object pointed to by the pointer - (*m_Pointer).Print(os); - return m_Pointer; + if (nullptr != m_RawPointer) + { + auto command = itk::SimpleMemberCommand::New(); + command->SetCallbackFunction(this, &WeakPointer::OnDeleteEvent); + m_ObserverTag = m_RawPointer->AddObserver(itk::DeleteEvent(), command); + } } - /// - /// \brief Gets called when the object is deleted or modified. - /// - void OnObjectDelete(const itk::Object *caller, const itk::EventObject &) + void RemoveDeleteEventObserver() { - // do not unsubscribe from this object. this would invalidate the iterator of the - // event listener vector (in itk::Object) and would lead to a crash - // instead: do nothing->object is going to be dead soon... - // this->RemoveDeleteAndModifiedObserver(); - m_Pointer = nullptr; - m_DeleteObserverTag = -1; - m_ModifiedObserverTag = -1; - ObjectDelete.Send(caller); + if (nullptr != m_RawPointer) + m_RawPointer->RemoveObserver(m_ObserverTag); } - void OnObjectModified(const itk::Object *caller, const itk::EventObject &) { ObjectModified.Send(caller); } - private: - void AddDeleteAndModifiedObserver() + void OnDeleteEvent() noexcept { - if (m_DeleteObserverTag == -1 && m_ModifiedObserverTag == -1 && m_Pointer != nullptr) - { - // add observer for delete event - typename itk::MemberCommand>::Pointer onObjectDelete = - itk::MemberCommand>::New(); + m_RawPointer = nullptr; - onObjectDelete->SetCallbackFunction(this, &WeakPointer::OnObjectDelete); - m_DeleteObserverTag = m_Pointer->AddObserver(itk::DeleteEvent(), onObjectDelete); + // Don't remove any observers from the observed object as it is about to + // die and can't handle this operation anymore. + } - // add observer for modified event - typename itk::MemberCommand>::Pointer onObjectModified = - itk::MemberCommand>::New(); + // The following comparison operators need access to class internals. + // All remaining comparison operators are implemented as non-member + // non-friend functions that use logical combinations of these non-member + // friend functions. - onObjectModified->SetCallbackFunction(this, &WeakPointer::OnObjectModified); - m_ModifiedObserverTag = m_Pointer->AddObserver(itk::ModifiedEvent(), onObjectModified); - } + friend bool operator ==(const WeakPointer &left, const WeakPointer &right) noexcept + { + return left.m_RawPointer == right.m_RawPointer; } - void RemoveDeleteAndModifiedObserver() + // Also covers comparisons to T::Pointer and T::ConstPointer as + // itk::SmartPointer can be implicitly converted to a raw pointer. + friend bool operator ==(const WeakPointer &left, const T *right) noexcept { - if (m_DeleteObserverTag >= 0 && m_ModifiedObserverTag >= 0 && m_Pointer != nullptr) - { - m_Pointer->RemoveObserver(m_DeleteObserverTag); - m_Pointer->RemoveObserver(m_ModifiedObserverTag); + return left.m_RawPointer == right; + } - m_DeleteObserverTag = -1; - m_ModifiedObserverTag = -1; - } + friend bool operator <(const WeakPointer &left, const WeakPointer &right) noexcept + { + // The specialization of std::less for any pointer type yields a total + // order, even if the built-in operator < doesn't. + return std::less()(left.m_RawPointer, right.m_RawPointer); + } + + friend bool operator <(const WeakPointer &left, std::nullptr_t right) noexcept + { + return std::less()(left.m_RawPointer, right); + } + + friend bool operator <(std::nullptr_t left, const WeakPointer &right) noexcept + { + return std::less()(left, right.m_RawPointer); } - long m_DeleteObserverTag; - long m_ModifiedObserverTag; + friend bool operator <(const WeakPointer &left, const T *right) noexcept + { + return std::less()(left.m_RawPointer, right); + } - /** The pointer to the object referred to by this smart pointer. */ - ObjectType *m_Pointer; + friend bool operator <(const T *left, const WeakPointer &right) noexcept + { + return std::less()(left, right.m_RawPointer); + } + + T *m_RawPointer; + + // m_ObserverTag is completely managed by the two methods + // AddDeleteEventObserver() and RemoveDeleteEventObserver(). There + // isn't any need to initialize or use it at all outside of these methods. + unsigned long m_ObserverTag; }; +} - template - std::ostream &operator<<(std::ostream &os, WeakPointer p) - { - p.Print(os); - return os; - } +template +bool operator !=(const mitk::WeakPointer &left, const mitk::WeakPointer &right) noexcept +{ + return !(left == right); +} + +template +bool operator <=(const mitk::WeakPointer &left, const mitk::WeakPointer &right) noexcept +{ + return !(right < left); +} + +template +bool operator >(const mitk::WeakPointer &left, const mitk::WeakPointer &right) noexcept +{ + return right < left; +} + +template +bool operator >=(const mitk::WeakPointer &left, const mitk::WeakPointer &right) noexcept +{ + return !(left < right); +} + +template +bool operator ==(const mitk::WeakPointer &left, std::nullptr_t) noexcept +{ + return !left; +} + +template +bool operator !=(const mitk::WeakPointer &left, std::nullptr_t right) noexcept +{ + return !(left == right); +} + +template +bool operator ==(std::nullptr_t, const mitk::WeakPointer &right) noexcept +{ + return !right; +} + +template +bool operator !=(std::nullptr_t left, const mitk::WeakPointer &right) noexcept +{ + return !(left == right); +} + +template +bool operator <=(const mitk::WeakPointer &left, std::nullptr_t right) noexcept +{ + return !(right < left); +} + +template +bool operator >(const mitk::WeakPointer &left, std::nullptr_t right) noexcept +{ + return right < left; +} + +template +bool operator >=(const mitk::WeakPointer &left, std::nullptr_t right) noexcept +{ + return !(left < right); +} + +template +bool operator <=(std::nullptr_t left, const mitk::WeakPointer &right) noexcept +{ + return !(right < left); +} + +template +bool operator >(std::nullptr_t left, const mitk::WeakPointer &right) noexcept +{ + return right < left; +} + +template +bool operator >=(std::nullptr_t left, const mitk::WeakPointer &right) noexcept +{ + return !(left < right); +} + +template +bool operator !=(const mitk::WeakPointer &left, const T *right) noexcept +{ + return !(left == right); +} + +template +bool operator <=(const mitk::WeakPointer &left, const T *right) noexcept +{ + return !(right < left); +} + +template +bool operator >(const mitk::WeakPointer &left, const T *right) noexcept +{ + return right < left; +} -} // end namespace mitk +template +bool operator >=(const mitk::WeakPointer &left, const T *right) noexcept +{ + return !(left < right); +} + +template +bool operator ==(const T *left, const mitk::WeakPointer &right) noexcept +{ + return right == left; +} + +template +bool operator !=(const T *left, const mitk::WeakPointer &right) noexcept +{ + return !(right == left); +} + +template +bool operator <=(const T *left, const mitk::WeakPointer &right) noexcept +{ + return !(right < left); +} + +template +bool operator >(const T *left, const mitk::WeakPointer &right) noexcept +{ + return right < left; +} + +template +bool operator >=(const T *left, const mitk::WeakPointer &right) noexcept +{ + return !(left < right); +} #endif