diff --git a/Modules/Core/include/mitkWeakPointer.h b/Modules/Core/include/mitkWeakPointer.h index a09ff7e94d..314f089a2e 100644 --- a/Modules/Core/include/mitkWeakPointer.h +++ b/Modules/Core/include/mitkWeakPointer.h @@ -1,400 +1,412 @@ /*=================================================================== 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 #include #include namespace mitk { template class WeakPointer final { public: + using DeleteEventCallbackType = std::function; + WeakPointer() noexcept : m_RawPointer(nullptr) { } WeakPointer(T *rawPointer) : m_RawPointer(rawPointer) { this->AddDeleteEventObserver(); } WeakPointer(const WeakPointer &other) : m_RawPointer(other.m_RawPointer) { this->AddDeleteEventObserver(); } WeakPointer(WeakPointer &&other) : m_RawPointer(other.m_RawPointer) { other.RemoveDeleteEventObserver(); other.m_RawPointer = nullptr; this->AddDeleteEventObserver(); } ~WeakPointer() noexcept { try { this->RemoveDeleteEventObserver(); } catch (...) { // Swallow. Otherwise, the application would terminate if another // exception is already propagating. } } // 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) { if (this != &other) { this->RemoveDeleteEventObserver(); m_RawPointer = other.m_RawPointer; this->AddDeleteEventObserver(); } return *this; } WeakPointer & operator =(WeakPointer &&other) { // No check for self-assignment as it is allowed to assume that the // parameter is a unique reference to this argument. this->RemoveDeleteEventObserver(); m_RawPointer = other.m_RawPointer; other.m_RawPointer = nullptr; this->AddDeleteEventObserver(); return *this; } WeakPointer & operator =(std::nullptr_t) { this->RemoveDeleteEventObserver(); m_RawPointer = nullptr; return *this; } WeakPointer & operator =(T *other) { if (m_RawPointer != other) { this->RemoveDeleteEventObserver(); m_RawPointer = other; this->AddDeleteEventObserver(); } return *this; } explicit operator bool() const noexcept { return nullptr != m_RawPointer; } bool IsExpired() const noexcept { return !*this; } itk::SmartPointer Lock() const { return m_RawPointer; } + void SetDeleteEventCallback(const DeleteEventCallbackType &callback) + { + m_DeleteEventCallback = callback; + } + private: void AddDeleteEventObserver() { if (nullptr != m_RawPointer) { auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &WeakPointer::OnDeleteEvent); m_ObserverTag = m_RawPointer->AddObserver(itk::DeleteEvent(), command); } } void RemoveDeleteEventObserver() { if (nullptr != m_RawPointer) m_RawPointer->RemoveObserver(m_ObserverTag); } void OnDeleteEvent() noexcept { - m_RawPointer = nullptr; - // Don't remove any observers from the observed object as it is about to // die and can't handle this operation anymore. + + m_RawPointer = nullptr; + + if (m_DeleteEventCallback) + m_DeleteEventCallback(); } // 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. friend bool operator ==(const WeakPointer &left, const WeakPointer &right) noexcept { return left.m_RawPointer == right.m_RawPointer; } // 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 { return left.m_RawPointer == right; } 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); } friend bool operator <(const WeakPointer &left, const T *right) noexcept { return std::less()(left.m_RawPointer, right); } 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; + + DeleteEventCallbackType m_DeleteEventCallback; }; } 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; } 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); } template bool operator !=(const mitk::WeakPointer &left, itk::SmartPointer right) noexcept { return !(left == right); } template bool operator <=(const mitk::WeakPointer &left, itk::SmartPointer right) noexcept { return !(right < left); } template bool operator >(const mitk::WeakPointer &left, itk::SmartPointer right) noexcept { return right < left; } template bool operator >=(const mitk::WeakPointer &left, itk::SmartPointer right) noexcept { return !(left < right); } template bool operator ==(itk::SmartPointer left, const mitk::WeakPointer &right) noexcept { return right == left; } template bool operator !=(itk::SmartPointer left, const mitk::WeakPointer &right) noexcept { return !(right == left); } template bool operator <=(itk::SmartPointer left, const mitk::WeakPointer &right) noexcept { return !(right < left); } template bool operator >(itk::SmartPointer left, const mitk::WeakPointer &right) noexcept { return right < left; } template bool operator >=(itk::SmartPointer left, const mitk::WeakPointer &right) noexcept { return !(left < right); } #endif diff --git a/Modules/Core/test/mitkWeakPointerTest.cpp b/Modules/Core/test/mitkWeakPointerTest.cpp index 19696a8ab5..2d033c535a 100644 --- a/Modules/Core/test/mitkWeakPointerTest.cpp +++ b/Modules/Core/test/mitkWeakPointerTest.cpp @@ -1,51 +1,60 @@ /*=================================================================== 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. ===================================================================*/ #include "mitkTestingMacros.h" #include #include int mitkWeakPointerTest(int /*argc*/, char * /*argv*/ []) { MITK_TEST_BEGIN("WeakPointer") + int deleteEventCallbackCalled = 0; + mitk::WeakPointer weakPointer; + + weakPointer.SetDeleteEventCallback([&deleteEventCallbackCalled]() + { + ++deleteEventCallbackCalled; + }); + mitk::WeakPointer weakPointer2; // Testing constructors and reference counting itk::Object::Pointer smartPointer = itk::Object::New(); mitk::WeakPointer weakPointer3(smartPointer); mitk::WeakPointer weakPointer4(weakPointer); { itk::Object::Pointer tmpSmartPointer(weakPointer.Lock()); itk::Object::Pointer tmpSmartPointer2(weakPointer2.Lock()); MITK_TEST_CONDITION_REQUIRED(tmpSmartPointer.GetPointer() == tmpSmartPointer2.GetPointer(), "Testing equal pointers"); } weakPointer = smartPointer; weakPointer2 = weakPointer; MITK_TEST_CONDITION_REQUIRED(1 == smartPointer->GetReferenceCount(), "Testing reference count"); smartPointer = nullptr; MITK_TEST_CONDITION_REQUIRED(weakPointer.IsExpired(), "Testing expired weak pointer (smart pointer assignment)"); MITK_TEST_CONDITION_REQUIRED(weakPointer2.IsExpired(), "Testing expired weak pointer (weak pointer assignment)"); MITK_TEST_CONDITION_REQUIRED(weakPointer3.IsExpired(), "Testing expired weak pointer (smart pointer constructor)"); - MITK_TEST_CONDITION_REQUIRED(weakPointer4.IsExpired(), "Testing expired weak pointer (copy constructor)") + MITK_TEST_CONDITION_REQUIRED(weakPointer4.IsExpired(), "Testing expired weak pointer (copy constructor)"); + MITK_TEST_CONDITION_REQUIRED(1 == deleteEventCallbackCalled, "Testing call of delete event callback"); MITK_TEST_END() }