/* * Copyright (c) 2005,2006 INRIA * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Mathieu Lacage */ #ifndef PTR_H #define PTR_H #include "assert.h" #include "deprecated.h" #include #include /** * \file * \ingroup ptr * ns3::Ptr smart pointer declaration and implementation. */ namespace ns3 { /** * \ingroup core * \defgroup ptr Smart Pointer * \brief Heap memory management. * * See \ref ns3::Ptr for implementation details. * * See \ref main-ptr.cc for example usage. */ /** * \ingroup ptr * * \brief Smart pointer class similar to \c boost::intrusive_ptr. * * This smart-pointer class assumes that the underlying * type provides a pair of \c Ref() and \c Unref() methods which are * expected to increment and decrement the internal reference count * of the object instance. You can add \c Ref() and \c Unref() * to a class simply by inheriting from ns3::SimpleRefCount<> * using the CRTP (`class Foo : public SimpleRefCount`) * * This implementation allows you to manipulate the smart pointer * as if it was a normal pointer: you can test if it is non-null, * compare it to other pointers of the same type, etc. * * It is possible to extract the raw pointer from this * smart pointer with the GetPointer() and PeekPointer() methods. * * If you want to store a `new Object()` into a smart pointer, * we recommend you to use the CreateObject<>() template function * to create the Object and store it in a smart pointer to avoid * memory leaks. These functions are really small convenience * functions and their goal is just is save you a small * bit of typing. If the Object does not inherit from Object * (or ObjectBase) there is also a convenience wrapper Create<>() * * \tparam T \explicit The type of the underlying object. */ template class Ptr { private: /** The pointer. */ T* m_ptr; /** * Helper to test for null pointer. * * \note This has been deprecated; \see operator bool() instead. * * This supports the "safe-bool" idiom, see `operator Tester * ()` */ // Don't deprecate the class because the warning fires // every time ptr.h is merely included, masking the real uses of Tester // Leave the macro here so we can find this later to actually remove it. class /* NS_DEPRECATED_3_37 ("see operator bool") */ Tester { public: // Delete operator delete to avoid misuse void operator delete(void*) = delete; }; /** Interoperate with const instances. */ friend class Ptr; /** * Get a permanent pointer to the underlying object. * * The underlying refcount is incremented prior * to returning to the caller so the caller is * responsible for calling Unref himself. * * \tparam U \deduced The actual type of the argument and return pointer. * \param [in] p Smart pointer * \return The pointer managed by this smart pointer. */ template friend U* GetPointer(const Ptr& p); /** * Get a temporary pointer to the underlying object. * * The underlying refcount is not incremented prior * to returning to the caller so the caller is not * responsible for calling Unref himself. * * \tparam U \deduced The actual type of the argument and return pointer. * \param [in] p Smart pointer * \return The pointer managed by this smart pointer. */ template friend U* PeekPointer(const Ptr& p); /** Mark this as a a reference by incrementing the reference count. */ inline void Acquire() const; public: /** Create an empty smart pointer */ Ptr(); /** * Create a smart pointer which points to the object pointed to by * the input raw pointer ptr. This method creates its own reference * to the pointed object. The caller is responsible for Unref()'ing * its own reference, and the smart pointer will eventually do the * same, so that object is deleted if no more references to it * remain. * * \param [in] ptr Raw pointer to manage */ Ptr(T* ptr); /** * Create a smart pointer which points to the object pointed to by * the input raw pointer ptr. * * \param [in] ptr Raw pointer to manage * \param [in] ref if set to true, this method calls Ref, otherwise, * it does not call Ref. */ Ptr(T* ptr, bool ref); /** * Copy by referencing the same underlying object. * * \param [in] o The other Ptr instance. */ Ptr(const Ptr& o); /** * Copy, removing \c const qualifier. * * \tparam U \deduced The type underlying the Ptr being copied. * \param [in] o The Ptr to copy. */ template Ptr(const Ptr& o); /** Destructor. */ ~Ptr(); /** * Assignment operator by referencing the same underlying object. * * \param [in] o The other Ptr instance. * \return A reference to self. */ Ptr& operator=(const Ptr& o); /** * An rvalue member access. * \returns A pointer to the underlying object. */ T* operator->() const; /** * An lvalue member access. * \returns A pointer to the underlying object. */ T* operator->(); /** * A \c const dereference. * \returns A pointer to the underlying object. */ T& operator*() const; /** * A dereference. * \returns A pointer to the underlying object. */ T& operator*(); /** * Test for non-NULL Ptr. * * \note This has been deprecated; \see operator bool() instead. * * This enables simple pointer checks like * \code * Ptr<...> p = ...; * if (p) ... * \endcode * This also disables deleting a Ptr * * This supports the "safe-bool" idiom; see [More C++ Idioms/Safe * bool](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool) */ NS_DEPRECATED_3_37("see operator bool") operator Tester*() const; /** * Test for non-NULL pointer. * * This enables simple pointer checks like * \code * Ptr<...> p = ...; * if (p) ... * if (!p) ... * \endcode * * The same construct works in the NS_ASSERT... and NS_ABORT... macros. * * \note Explicit tests against `0`, `NULL` or `nullptr` are not supported. * All these cases will fail to compile: * \code * if (p != nullptr {...} // Should be `if (p)` * if (p != NULL) {...} * if (p != 0) {...} * * if (p == nullptr {...} // Should be `if (!p)` * if (p == NULL) {...} * if (p == 0) {...} * \endcode * Just use `if (p)` or `if (!p)` as indicated. * * \note NS_TEST... invocations should be written as follows: * \code * // p should be non-NULL * NS_TEST...NE... (p, nullptr, ...); * // p should be NULL * NS_TEST...EQ... (p, nullptr, ...); * \endcode * * \note Unfortunately return values are not * "contextual conversion expression" contexts, * so you need to explicitly cast return values to bool: * \code * bool f (...) * { * Ptr<...> p = ...; * return (bool)(p); * } * \endcode * * \returns \c true if the underlying pointer is non-NULL. */ explicit operator bool() const; }; /** * \ingroup ptr * Create class instances by constructors with varying numbers * of arguments and return them by Ptr. * * This template work for any class \c T derived from ns3::SimpleRefCount * * \see CreateObject for methods to create derivatives of ns3::Object */ /** @{ */ /** * \tparam T \explicit The type of class object to create. * \tparam Ts \deduced Types of the constructor arguments. * \param [in] args Constructor arguments. * \return A Ptr to the newly created \c T. */ template Ptr Create(Ts&&... args); /** @}*/ /** * \ingroup ptr * Output streamer. * \tparam T \deduced The type of the underlying Object. * \param [in,out] os The output stream. * \param [in] p The Ptr. * \returns The stream. */ template std::ostream& operator<<(std::ostream& os, const Ptr& p); /** * \ingroup ptr * Equality operator. * * This enables code such as * \code * Ptr<...> p = ...; * Ptr<...> q = ...; * if (p == q) ... * \endcode * * Note that either \c p or \c q could also be ordinary pointers * to the underlying object. * * \tparam T1 \deduced Type of the object on the lhs. * \tparam T2 \deduced Type of the object on the rhs. * \param [in] lhs The left operand. * \param [in] rhs The right operand. * \return \c true if the operands point to the same underlying object. */ /** @{ */ template bool operator==(const Ptr& lhs, T2 const* rhs); template bool operator==(T1 const* lhs, Ptr& rhs); template bool operator==(const Ptr& lhs, const Ptr& rhs); /**@}*/ /** * \ingroup ptr * Specialization for comparison to \c nullptr * \copydoc operator==(Ptrconst&,Ptrconst&) */ template typename std::enable_if::value, bool>::type operator==( const Ptr& lhs, T2 rhs); /** * \ingroup ptr * Inequality operator. * * This enables code such as * \code * Ptr<...> p = ...; * Ptr<...> q = ...; * if (p != q) ... * \endcode * * Note that either \c p or \c q could also be ordinary pointers * to the underlying object. * * \tparam T1 \deduced Type of the object on the lhs. * \tparam T2 \deduced Type of the object on the rhs. * \param [in] lhs The left operand. * \param [in] rhs The right operand. * \return \c true if the operands point to the same underlying object. */ /** @{ */ template bool operator!=(const Ptr& lhs, T2 const* rhs); template bool operator!=(T1 const* lhs, Ptr& rhs); template bool operator!=(const Ptr& lhs, const Ptr& rhs); /**@}*/ /** * \ingroup ptr * Specialization for comparison to \c nullptr * \copydoc operator==(Ptrconst&,Ptrconst&) */ template typename std::enable_if::value, bool>::type operator!=( const Ptr& lhs, T2 rhs); /** * \ingroup ptr * Comparison operator applied to the underlying pointers. * * \tparam T \deduced The type of the operands. * \param [in] lhs The left operand. * \param [in] rhs The right operand. * \return The comparison on the underlying pointers. */ /** @{ */ template bool operator<(const Ptr& lhs, const Ptr& rhs); template bool operator<(const Ptr& lhs, const Ptr& rhs); template bool operator<(const Ptr& lhs, const Ptr& rhs); template bool operator<=(const Ptr& lhs, const Ptr& rhs); template bool operator>(const Ptr& lhs, const Ptr& rhs); template bool operator>=(const Ptr& lhs, const Ptr& rhs); /** @} */ /** * Return a copy of \c p with its stored pointer const casted from * \c T2 to \c T1. * * \tparam T1 \deduced The type to return in a Ptr. * \tparam T2 \deduced The type of the underlying object. * \param [in] p The original \c const Ptr. * \return A non-const Ptr. */ template Ptr const_pointer_cast(const Ptr& p); // Duplicate of struct CallbackTraits as defined in callback.h template struct CallbackTraits; /** * \ingroup callbackimpl * * Trait class to convert a pointer into a reference, * used by MemPtrCallBackImpl. * * This is the specialization for Ptr types. * * \tparam T \deduced The type of the underlying object. */ template struct CallbackTraits> { /** * \param [in] p Object pointer * \return A reference to the object pointed to by p */ static T& GetReference(const Ptr p) { return *PeekPointer(p); } }; // Duplicate of struct EventMemberImplObjTraits as defined in make-event.h // We repeat it here to declare a specialization on Ptr // without making this header dependent on make-event.h template struct EventMemberImplObjTraits; /** * \ingroup makeeventmemptr * Helper for the MakeEvent functions which take a class method. * * This is the specialization for Ptr types. * * \tparam T \deduced The type of the underlying object. */ template struct EventMemberImplObjTraits> { /** * \param [in] p Object pointer * \return A reference to the object pointed to by p */ static T& GetReference(Ptr p) { return *PeekPointer(p); } }; } // namespace ns3 namespace ns3 { /************************************************* * friend non-member function implementations ************************************************/ template Ptr Create(Ts&&... args) { return Ptr(new T(std::forward(args)...), false); } template U* PeekPointer(const Ptr& p) { return p.m_ptr; } template U* GetPointer(const Ptr& p) { p.Acquire(); return p.m_ptr; } template std::ostream& operator<<(std::ostream& os, const Ptr& p) { os << PeekPointer(p); return os; } template bool operator==(const Ptr& lhs, T2 const* rhs) { return PeekPointer(lhs) == rhs; } template bool operator==(T1 const* lhs, Ptr& rhs) { return lhs == PeekPointer(rhs); } template bool operator!=(const Ptr& lhs, T2 const* rhs) { return PeekPointer(lhs) != rhs; } template bool operator!=(T1 const* lhs, Ptr& rhs) { return lhs != PeekPointer(rhs); } template bool operator==(const Ptr& lhs, const Ptr& rhs) { return PeekPointer(lhs) == PeekPointer(rhs); } template bool operator!=(const Ptr& lhs, const Ptr& rhs) { return PeekPointer(lhs) != PeekPointer(rhs); } template typename std::enable_if::value, bool>::type operator==(const Ptr& lhs, T2 rhs) { return PeekPointer(lhs) == nullptr; } template typename std::enable_if::value, bool>::type operator!=(const Ptr& lhs, T2 rhs) { return PeekPointer(lhs) != nullptr; } template bool operator<(const Ptr& lhs, const Ptr& rhs) { return PeekPointer(lhs) < PeekPointer(rhs); } template bool operator<(const Ptr& lhs, const Ptr& rhs) { return PeekPointer(lhs) < PeekPointer(rhs); } template bool operator<(const Ptr& lhs, const Ptr& rhs) { return PeekPointer(lhs) < PeekPointer(rhs); } template bool operator<=(const Ptr& lhs, const Ptr& rhs) { return PeekPointer(lhs) <= PeekPointer(rhs); } template bool operator>(const Ptr& lhs, const Ptr& rhs) { return PeekPointer(lhs) > PeekPointer(rhs); } template bool operator>=(const Ptr& lhs, const Ptr& rhs) { return PeekPointer(lhs) >= PeekPointer(rhs); } /** * Cast a Ptr. * * \tparam T1 \deduced The desired type to cast to. * \tparam T2 \deduced The type of the original Ptr. * \param [in] p The original Ptr. * \return The result of the cast. */ /** @{ */ template Ptr ConstCast(const Ptr& p) { return Ptr(const_cast(PeekPointer(p))); } template Ptr DynamicCast(const Ptr& p) { return Ptr(dynamic_cast(PeekPointer(p))); } template Ptr StaticCast(const Ptr& p) { return Ptr(static_cast(PeekPointer(p))); } /** @} */ /** * Return a deep copy of a Ptr. * * \tparam T \deduced The type of the underlying object. * \param [in] object The object Ptr to copy. * \returns The copy. */ /** @{ */ template Ptr Copy(Ptr object) { Ptr p = Ptr(new T(*PeekPointer(object)), false); return p; } template Ptr Copy(Ptr object) { Ptr p = Ptr(new T(*PeekPointer(object)), false); return p; } /** @} */ /**************************************************** * Member method implementations. ***************************************************/ template void Ptr::Acquire() const { if (m_ptr != nullptr) { m_ptr->Ref(); } } template Ptr::Ptr() : m_ptr(nullptr) { } template Ptr::Ptr(T* ptr) : m_ptr(ptr) { Acquire(); } template Ptr::Ptr(T* ptr, bool ref) : m_ptr(ptr) { if (ref) { Acquire(); } } template Ptr::Ptr(const Ptr& o) : m_ptr(nullptr) { T* ptr = PeekPointer(o); if (ptr != nullptr) { m_ptr = ptr; Acquire(); } } template template Ptr::Ptr(const Ptr& o) : m_ptr(PeekPointer(o)) { Acquire(); } template Ptr::~Ptr() { if (m_ptr != nullptr) { m_ptr->Unref(); } } template Ptr& Ptr::operator=(const Ptr& o) { if (&o == this) { return *this; } if (m_ptr != nullptr) { m_ptr->Unref(); } m_ptr = o.m_ptr; Acquire(); return *this; } template T* Ptr::operator->() { NS_ASSERT_MSG(m_ptr, "Attempted to dereference zero pointer"); return m_ptr; } template T* Ptr::operator->() const { NS_ASSERT_MSG(m_ptr, "Attempted to dereference zero pointer"); return m_ptr; } template T& Ptr::operator*() const { NS_ASSERT_MSG(m_ptr, "Attempted to dereference zero pointer"); return *m_ptr; } template T& Ptr::operator*() { NS_ASSERT_MSG(m_ptr, "Attempted to dereference zero pointer"); return *m_ptr; } template Ptr::operator Tester*() const // NS_DEPRECATED_3_37 { if (m_ptr == 0) { return 0; } static Tester test; return &test; } template Ptr::operator bool() const { return m_ptr != nullptr; } } // namespace ns3 /**************************************************** * Global Functions (outside namespace ns3) ***************************************************/ /** * \ingroup ptr * Hashing functor taking a `Ptr` and returning a @c std::size_t. * For use with `unordered_map` and `unordered_set`. * * \note When a `Ptr` is used in a container the lifetime of the underlying * object is at least as long as the container. In other words, * you need to remove the object from the container when you are done with * it, otherwise the object will persist until the container itself is * deleted. * * \tparam T \deduced The type held by the `Ptr` */ template struct std::hash> { /** * The functor. * \param p The `Ptr` value to hash. * \return the hash */ std::size_t operator()(ns3::Ptr p) const { return std::hash()(ns3::PeekPointer(p)); } }; #endif /* PTR_H */