/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkSmartPointer_h #define itkSmartPointer_h #include #include #include #include "itkConfigure.h" namespace itk { /** \class SmartPointer * \brief Implements transparent reference counting. * * SmartPointer implements reference counting by overloading * operator -> (and *) among others. This allows natural interface * to the class referred to by the pointer without having to invoke * special Register()/UnRegister() methods directly. * * To compile / test this class * Windows: cl SmartPointerTest.cxx; .\\SmartPointerTest.exe * linux: c++ SmartPointerTest.cxx ./a.out * other: CCcompiler SmartPointerTest.cxx ./a.out * * The state of the SmartPointer after a `move` is with a value of * `nullptr`. * * \ingroup ITKSystemObjects * \ingroup DataAccess * \ingroup ITKCommon */ template class SmartPointer { public: using ObjectType = TObjectType; template using EnableIfConvertible = typename std::enable_if>; /** Default-constructor */ constexpr SmartPointer() noexcept = default; /** Copy constructor */ SmartPointer(const SmartPointer & p) noexcept : m_Pointer(p.m_Pointer) { this->Register(); } /** Constructor for implicit conversion from nullptr */ constexpr SmartPointer(std::nullptr_t) noexcept {} /** constructor with implicit conversion of pointer type */ template ::type> SmartPointer(const SmartPointer & p) noexcept : m_Pointer(p.m_Pointer) { this->Register(); } /** Move constructor */ SmartPointer(SmartPointer && p) noexcept : m_Pointer(p.m_Pointer) { p.m_Pointer = nullptr; } /** move constructor with implicit conversion of pointer type */ template ::type> SmartPointer(SmartPointer && p) noexcept : m_Pointer(p.m_Pointer) { p.m_Pointer = nullptr; } /** Constructor to pointer p */ SmartPointer(ObjectType * p) noexcept : m_Pointer(p) { this->Register(); } /** Destructor */ ~SmartPointer() { this->UnRegister(); } /** Overload operator -> */ ObjectType * operator->() const noexcept { return m_Pointer; } ObjectType & operator*() const noexcept { return *m_Pointer; } explicit operator bool() const noexcept { return m_Pointer != nullptr; } /** Return pointer to object. */ operator ObjectType *() const noexcept { return m_Pointer; } /** Test if the pointer is not NULL. */ bool IsNotNull() const noexcept { return m_Pointer != nullptr; } /** Test if the pointer is NULL. */ bool IsNull() const noexcept { return m_Pointer == nullptr; } /** Access function to pointer. */ ObjectType * GetPointer() const noexcept { return m_Pointer; } /** Returns the stored (raw) pointer. Equivalent to `GetPointer()`, but then following the Standard C++ Library naming * conversion (like `std::shared_ptr::get()`). */ ObjectType * get() const noexcept { return m_Pointer; } /** Overload operator assignment. * * This method is also implicitly used for move semantics. * Additionally, it relies on constructors for additional conversion * for pointer types. */ // cppcheck-suppress operatorEqVarError SmartPointer & operator=(SmartPointer r) noexcept { // The Copy-Swap idiom is used, with the implicit copy from the // value-based argument r (intentionally not reference). If a move // is requested it will be moved into r with the move constructor. this->Swap(r); return *this; } SmartPointer & operator=(std::nullptr_t) noexcept { this->UnRegister(); this->m_Pointer = nullptr; return *this; } /** Function to print object pointed to */ ObjectType * Print(std::ostream & os) const { if (this->IsNull()) { os << "(null)"; } else { // This prints the object pointed to by the pointer m_Pointer->Print(os); } return m_Pointer; } #if !defined(ITK_LEGACY_REMOVE) void swap(SmartPointer & other) noexcept { this->Swap(other); } #endif void Swap(SmartPointer & other) noexcept { ObjectType * tmp = this->m_Pointer; this->m_Pointer = other.m_Pointer; other.m_Pointer = tmp; } private: /** The pointer to the object referred to by this smart pointer. */ ObjectType * m_Pointer{ nullptr }; template friend class SmartPointer; void Register() noexcept { if (m_Pointer) { m_Pointer->Register(); } } void UnRegister() noexcept { if (m_Pointer) { m_Pointer->UnRegister(); } } }; /** Comparison of pointers. Equality comparison. */ template bool operator==(const SmartPointer & l, const SmartPointer & r) noexcept { return (l.GetPointer() == r.GetPointer()); } template bool operator==(const SmartPointer & l, std::nullptr_t) noexcept { return (l.GetPointer() == nullptr); } template bool operator==(std::nullptr_t, const SmartPointer & r) noexcept { return (nullptr == r.GetPointer()); } /** Comparison of pointers. Not equal comparison. */ template bool operator!=(const SmartPointer & l, const SmartPointer & r) noexcept { return (l.GetPointer() != r.GetPointer()); } template bool operator!=(const SmartPointer & l, std::nullptr_t) noexcept { return (l.GetPointer() != nullptr); } template bool operator!=(std::nullptr_t, const SmartPointer & r) noexcept { return (nullptr != r.GetPointer()); } /** Comparison of pointers. Less than comparison. */ template bool operator<(const SmartPointer & l, const SmartPointer & r) noexcept { return (l.GetPointer() < r.GetPointer()); } /** Comparison of pointers. Greater than comparison. */ template bool operator>(const SmartPointer & l, const SmartPointer & r) noexcept { return (l.GetPointer() > r.GetPointer()); } /** Comparison of pointers. Less than or equal to comparison. */ template bool operator<=(const SmartPointer & l, const SmartPointer & r) noexcept { return (l.GetPointer() <= r.GetPointer()); } /** Comparison of pointers. Greater than or equal to comparison. */ template bool operator>=(const SmartPointer & l, const SmartPointer & r) noexcept { return (l.GetPointer() >= r.GetPointer()); } template std::ostream & operator<<(std::ostream & os, const SmartPointer p) { p.Print(os); return os; } template inline void swap(SmartPointer & a, SmartPointer & b) noexcept { a.Swap(b); } } // end namespace itk #endif