A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
ptr.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2005,2006 INRIA
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 */
8
9#ifndef PTR_H
10#define PTR_H
11
12#include "assert.h"
13
14#include <iostream>
15#include <stdint.h>
16
17/**
18 * \file
19 * \ingroup ptr
20 * ns3::Ptr smart pointer declaration and implementation.
21 */
22
23namespace ns3
24{
25
26/**
27 * \ingroup core
28 * \defgroup ptr Smart Pointer
29 * \brief Heap memory management.
30 *
31 * See \ref ns3::Ptr for implementation details.
32 *
33 * See \ref main-ptr.cc for example usage.
34 */
35/**
36 * \ingroup ptr
37 *
38 * \brief Smart pointer class similar to \c boost::intrusive_ptr.
39 *
40 * This smart-pointer class assumes that the underlying
41 * type provides a pair of \c Ref() and \c Unref() methods which are
42 * expected to increment and decrement the internal reference count
43 * of the object instance. You can add \c Ref() and \c Unref()
44 * to a class simply by inheriting from ns3::SimpleRefCount<>
45 * using the CRTP (`class Foo : public SimpleRefCount<Foo>`)
46 *
47 * This implementation allows you to manipulate the smart pointer
48 * as if it was a normal pointer: you can test if it is non-null,
49 * compare it to other pointers of the same type, etc.
50 *
51 * It is possible to extract the raw pointer from this
52 * smart pointer with the GetPointer() and PeekPointer() methods.
53 *
54 * If you want to store a `new Object()` into a smart pointer,
55 * we recommend you to use the CreateObject<>() template function
56 * to create the Object and store it in a smart pointer to avoid
57 * memory leaks. These functions are really small convenience
58 * functions and their goal is just is save you a small
59 * bit of typing. If the Object does not inherit from Object
60 * (or ObjectBase) there is also a convenience wrapper Create<>()
61 *
62 * \tparam T \explicit The type of the underlying object.
63 */
64template <typename T>
65class Ptr
66{
67 private:
68 /** The pointer. */
70
71 /** Interoperate with const instances. */
72 friend class Ptr<const T>;
73
74 /**
75 * Get a permanent pointer to the underlying object.
76 *
77 * The underlying refcount is incremented prior
78 * to returning to the caller so the caller is
79 * responsible for calling Unref himself.
80 *
81 * \tparam U \deduced The actual type of the argument and return pointer.
82 * \param [in] p Smart pointer
83 * \return The pointer managed by this smart pointer.
84 */
85 template <typename U>
86 friend U* GetPointer(const Ptr<U>& p);
87 /**
88 * Get a temporary pointer to the underlying object.
89 *
90 * The underlying refcount is not incremented prior
91 * to returning to the caller so the caller is not
92 * responsible for calling Unref himself.
93 *
94 * \tparam U \deduced The actual type of the argument and return pointer.
95 * \param [in] p Smart pointer
96 * \return The pointer managed by this smart pointer.
97 */
98 template <typename U>
99 friend U* PeekPointer(const Ptr<U>& p);
100
101 /** Mark this as a a reference by incrementing the reference count. */
102 inline void Acquire() const;
103
104 public:
105 /** Create an empty smart pointer */
107 /**
108 * Create a smart pointer which points to the object pointed to by
109 * the input raw pointer ptr. This method creates its own reference
110 * to the pointed object. The caller is responsible for Unref()'ing
111 * its own reference, and the smart pointer will eventually do the
112 * same, so that object is deleted if no more references to it
113 * remain.
114 *
115 * \param [in] ptr Raw pointer to manage
116 */
117 Ptr(T* ptr);
118 /**
119 * Create a smart pointer which points to the object pointed to by
120 * the input raw pointer ptr.
121 *
122 * \param [in] ptr Raw pointer to manage
123 * \param [in] ref if set to true, this method calls Ref, otherwise,
124 * it does not call Ref.
125 */
126 Ptr(T* ptr, bool ref);
127 /**
128 * Copy by referencing the same underlying object.
129 *
130 * \param [in] o The other Ptr instance.
131 */
132 Ptr(const Ptr& o);
133 /**
134 * Copy, removing \c const qualifier.
135 *
136 * \tparam U \deduced The type underlying the Ptr being copied.
137 * \param [in] o The Ptr to copy.
138 */
139 template <typename U>
140 Ptr(const Ptr<U>& o);
141 /** Destructor. */
143 /**
144 * Assignment operator by referencing the same underlying object.
145 *
146 * \param [in] o The other Ptr instance.
147 * \return A reference to self.
148 */
149 Ptr<T>& operator=(const Ptr& o);
150 /**
151 * An rvalue member access.
152 * \returns A pointer to the underlying object.
153 */
154 T* operator->() const;
155 /**
156 * An lvalue member access.
157 * \returns A pointer to the underlying object.
158 */
160 /**
161 * A \c const dereference.
162 * \returns A pointer to the underlying object.
163 */
164 T& operator*() const;
165 /**
166 * A dereference.
167 * \returns A pointer to the underlying object.
168 */
170
171 /**
172 * Test for non-NULL pointer.
173 *
174 * This enables simple pointer checks like
175 * \code
176 * Ptr<...> p = ...;
177 * if (p) ...
178 * if (!p) ...
179 * \endcode
180 *
181 * The same construct works in the NS_ASSERT... and NS_ABORT... macros.
182 *
183 * \note Explicit tests against `0`, `NULL` or `nullptr` are not supported.
184 * All these cases will fail to compile:
185 * \code
186 * if (p != nullptr {...} // Should be `if (p)`
187 * if (p != NULL) {...}
188 * if (p != 0) {...}
189 *
190 * if (p == nullptr {...} // Should be `if (!p)`
191 * if (p == NULL) {...}
192 * if (p == 0) {...}
193 * \endcode
194 * Just use `if (p)` or `if (!p)` as indicated.
195 *
196 * \note NS_TEST... invocations should be written as follows:
197 * \code
198 * // p should be non-NULL
199 * NS_TEST...NE... (p, nullptr, ...);
200 * // p should be NULL
201 * NS_TEST...EQ... (p, nullptr, ...);
202 * \endcode
203 *
204 * \note Unfortunately return values are not
205 * "contextual conversion expression" contexts,
206 * so you need to explicitly cast return values to bool:
207 * \code
208 * bool f (...)
209 * {
210 * Ptr<...> p = ...;
211 * return (bool)(p);
212 * }
213 * \endcode
214 *
215 * \returns \c true if the underlying pointer is non-NULL.
216 */
217 explicit operator bool() const;
218};
219
220/**
221 * \ingroup ptr
222 * Create class instances by constructors with varying numbers
223 * of arguments and return them by Ptr.
224 *
225 * This template work for any class \c T derived from ns3::SimpleRefCount
226 *
227 * \see CreateObject for methods to create derivatives of ns3::Object
228 */
229/** @{ */
230/**
231 * \tparam T \explicit The type of class object to create.
232 * \tparam Ts \deduced Types of the constructor arguments.
233 * \param [in] args Constructor arguments.
234 * \return A Ptr to the newly created \c T.
235 */
236template <typename T, typename... Ts>
237Ptr<T> Create(Ts&&... args);
238
239/** @}*/
240
241/**
242 * \ingroup ptr
243 * Output streamer.
244 * \tparam T \deduced The type of the underlying Object.
245 * \param [in,out] os The output stream.
246 * \param [in] p The Ptr.
247 * \returns The stream.
248 */
249template <typename T>
250std::ostream& operator<<(std::ostream& os, const Ptr<T>& p);
251
252/**
253 * \ingroup ptr
254 * Equality operator.
255 *
256 * This enables code such as
257 * \code
258 * Ptr<...> p = ...;
259 * Ptr<...> q = ...;
260 * if (p == q) ...
261 * \endcode
262 *
263 * Note that either \c p or \c q could also be ordinary pointers
264 * to the underlying object.
265 *
266 * \tparam T1 \deduced Type of the object on the lhs.
267 * \tparam T2 \deduced Type of the object on the rhs.
268 * \param [in] lhs The left operand.
269 * \param [in] rhs The right operand.
270 * \return \c true if the operands point to the same underlying object.
271 */
272/** @{ */
273template <typename T1, typename T2>
274bool operator==(const Ptr<T1>& lhs, T2 const* rhs);
275
276template <typename T1, typename T2>
277bool operator==(T1 const* lhs, Ptr<T2>& rhs);
278
279template <typename T1, typename T2>
280bool operator==(const Ptr<T1>& lhs, const Ptr<T2>& rhs);
281/**@}*/
282
283/**
284 * \ingroup ptr
285 * Specialization for comparison to \c nullptr
286 * \copydoc operator==(Ptr<T1>const&,Ptr<T2>const&)
287 */
288template <typename T1, typename T2>
289std::enable_if_t<std::is_same_v<T2, std::nullptr_t>, bool> operator==(const Ptr<T1>& lhs, T2 rhs);
290
291/**
292 * \ingroup ptr
293 * Inequality operator.
294 *
295 * This enables code such as
296 * \code
297 * Ptr<...> p = ...;
298 * Ptr<...> q = ...;
299 * if (p != q) ...
300 * \endcode
301 *
302 * Note that either \c p or \c q could also be ordinary pointers
303 * to the underlying object.
304 *
305 * \tparam T1 \deduced Type of the object on the lhs.
306 * \tparam T2 \deduced Type of the object on the rhs.
307 * \param [in] lhs The left operand.
308 * \param [in] rhs The right operand.
309 * \return \c true if the operands point to the same underlying object.
310 */
311/** @{ */
312template <typename T1, typename T2>
313bool operator!=(const Ptr<T1>& lhs, T2 const* rhs);
314
315template <typename T1, typename T2>
316bool operator!=(T1 const* lhs, Ptr<T2>& rhs);
317
318template <typename T1, typename T2>
319bool operator!=(const Ptr<T1>& lhs, const Ptr<T2>& rhs);
320/**@}*/
321
322/**
323 * \ingroup ptr
324 * Specialization for comparison to \c nullptr
325 * \copydoc operator==(Ptr<T1>const&,Ptr<T2>const&)
326 */
327template <typename T1, typename T2>
328std::enable_if_t<std::is_same_v<T2, std::nullptr_t>, bool> operator!=(const Ptr<T1>& lhs, T2 rhs);
329
330/**
331 * \ingroup ptr
332 * Comparison operator applied to the underlying pointers.
333 *
334 * \tparam T \deduced The type of the operands.
335 * \param [in] lhs The left operand.
336 * \param [in] rhs The right operand.
337 * \return The comparison on the underlying pointers.
338 */
339/** @{ */
340template <typename T>
341bool operator<(const Ptr<T>& lhs, const Ptr<T>& rhs);
342template <typename T>
343bool operator<(const Ptr<T>& lhs, const Ptr<const T>& rhs);
344template <typename T>
345bool operator<(const Ptr<const T>& lhs, const Ptr<T>& rhs);
346template <typename T>
347bool operator<=(const Ptr<T>& lhs, const Ptr<T>& rhs);
348template <typename T>
349bool operator>(const Ptr<T>& lhs, const Ptr<T>& rhs);
350template <typename T>
351bool operator>=(const Ptr<T>& lhs, const Ptr<T>& rhs);
352/** @} */
353
354/**
355 * Return a copy of \c p with its stored pointer const casted from
356 * \c T2 to \c T1.
357 *
358 * \tparam T1 \deduced The type to return in a Ptr.
359 * \tparam T2 \deduced The type of the underlying object.
360 * \param [in] p The original \c const Ptr.
361 * \return A non-const Ptr.
362 */
363template <typename T1, typename T2>
365
366// Duplicate of struct CallbackTraits<T> as defined in callback.h
367template <typename T>
369
370/**
371 * \ingroup callbackimpl
372 *
373 * Trait class to convert a pointer into a reference,
374 * used by MemPtrCallBackImpl.
375 *
376 * This is the specialization for Ptr types.
377 *
378 * \tparam T \deduced The type of the underlying object.
379 */
380template <typename T>
382{
383 /**
384 * \param [in] p Object pointer
385 * \return A reference to the object pointed to by p
386 */
387 static T& GetReference(const Ptr<T> p)
388 {
389 return *PeekPointer(p);
390 }
391};
392
393namespace internal
394{
395
396// Duplicate of struct EventMemberImplObjTraits<T> as defined in make-event.h
397// We repeat it here to declare a specialization on Ptr<T>
398// without making this header dependent on make-event.h
399template <typename T>
401
402/**
403 * \ingroup makeeventmemptr
404 * Helper for the MakeEvent functions which take a class method.
405 *
406 * This is the specialization for Ptr types.
407 *
408 * \tparam T \deduced The type of the underlying object.
409 */
410template <typename T>
412{
413 /**
414 * \param [in] p Object pointer
415 * \return A reference to the object pointed to by p
416 */
417 static T& GetReference(Ptr<T> p)
418 {
419 return *PeekPointer(p);
420 }
421};
422
423} // namespace internal
424
425} // namespace ns3
426
427namespace ns3
428{
429
430/*************************************************
431 * friend non-member function implementations
432 ************************************************/
433
434template <typename T, typename... Ts>
435Ptr<T>
436Create(Ts&&... args)
437{
438 return Ptr<T>(new T(std::forward<Ts>(args)...), false);
439}
440
441template <typename U>
442U*
444{
445 return p.m_ptr;
446}
447
448template <typename U>
449U*
451{
452 p.Acquire();
453 return p.m_ptr;
454}
455
456template <typename T>
457std::ostream&
458operator<<(std::ostream& os, const Ptr<T>& p)
459{
460 os << PeekPointer(p);
461 return os;
462}
463
464template <typename T1, typename T2>
465bool
466operator==(const Ptr<T1>& lhs, T2 const* rhs)
467{
468 return PeekPointer(lhs) == rhs;
469}
470
471template <typename T1, typename T2>
472bool
473operator==(T1 const* lhs, Ptr<T2>& rhs)
474{
475 return lhs == PeekPointer(rhs);
476}
477
478template <typename T1, typename T2>
479bool
480operator!=(const Ptr<T1>& lhs, T2 const* rhs)
481{
482 return PeekPointer(lhs) != rhs;
483}
484
485template <typename T1, typename T2>
486bool
487operator!=(T1 const* lhs, Ptr<T2>& rhs)
488{
489 return lhs != PeekPointer(rhs);
490}
491
492template <typename T1, typename T2>
493bool
494operator==(const Ptr<T1>& lhs, const Ptr<T2>& rhs)
495{
496 return PeekPointer(lhs) == PeekPointer(rhs);
497}
498
499template <typename T1, typename T2>
500bool
501operator!=(const Ptr<T1>& lhs, const Ptr<T2>& rhs)
502{
503 return PeekPointer(lhs) != PeekPointer(rhs);
504}
505
506template <typename T1, typename T2>
507std::enable_if_t<std::is_same_v<T2, std::nullptr_t>, bool>
508operator==(const Ptr<T1>& lhs, T2 rhs)
509{
510 return PeekPointer(lhs) == nullptr;
511}
512
513template <typename T1, typename T2>
514std::enable_if_t<std::is_same_v<T2, std::nullptr_t>, bool>
515operator!=(const Ptr<T1>& lhs, T2 rhs)
516{
517 return PeekPointer(lhs) != nullptr;
518}
519
520template <typename T>
521bool
522operator<(const Ptr<T>& lhs, const Ptr<T>& rhs)
523{
524 return PeekPointer<T>(lhs) < PeekPointer<T>(rhs);
525}
526
527template <typename T>
528bool
529operator<(const Ptr<T>& lhs, const Ptr<const T>& rhs)
530{
531 return PeekPointer<T>(lhs) < PeekPointer<const T>(rhs);
532}
533
534template <typename T>
535bool
536operator<(const Ptr<const T>& lhs, const Ptr<T>& rhs)
537{
538 return PeekPointer<const T>(lhs) < PeekPointer<T>(rhs);
539}
540
541template <typename T>
542bool
543operator<=(const Ptr<T>& lhs, const Ptr<T>& rhs)
544{
545 return PeekPointer<T>(lhs) <= PeekPointer<T>(rhs);
546}
547
548template <typename T>
549bool
550operator>(const Ptr<T>& lhs, const Ptr<T>& rhs)
551{
552 return PeekPointer<T>(lhs) > PeekPointer<T>(rhs);
553}
554
555template <typename T>
556bool
557operator>=(const Ptr<T>& lhs, const Ptr<T>& rhs)
558{
559 return PeekPointer<T>(lhs) >= PeekPointer<T>(rhs);
560}
561
562/**
563 * Cast a Ptr.
564 *
565 * \tparam T1 \deduced The desired type to cast to.
566 * \tparam T2 \deduced The type of the original Ptr.
567 * \param [in] p The original Ptr.
568 * \return The result of the cast.
569 */
570/** @{ */
571template <typename T1, typename T2>
572Ptr<T1>
574{
575 return Ptr<T1>(const_cast<T1*>(PeekPointer(p)));
576}
577
578template <typename T1, typename T2>
579Ptr<T1>
581{
582 return Ptr<T1>(dynamic_cast<T1*>(PeekPointer(p)));
583}
584
585template <typename T1, typename T2>
586Ptr<T1>
588{
589 return Ptr<T1>(static_cast<T1*>(PeekPointer(p)));
590}
591
592/** @} */
593
594/**
595 * Return a deep copy of a Ptr.
596 *
597 * \tparam T \deduced The type of the underlying object.
598 * \param [in] object The object Ptr to copy.
599 * \returns The copy.
600 */
601/** @{ */
602template <typename T>
603Ptr<T>
605{
606 Ptr<T> p = Ptr<T>(new T(*PeekPointer(object)), false);
607 return p;
608}
609
610template <typename T>
611Ptr<T>
612Copy(Ptr<const T> object)
613{
614 Ptr<T> p = Ptr<T>(new T(*PeekPointer(object)), false);
615 return p;
616}
617
618/** @} */
619
620/****************************************************
621 * Member method implementations.
622 ***************************************************/
623
624template <typename T>
625void
627{
628 if (m_ptr != nullptr)
629 {
630 m_ptr->Ref();
631 }
632}
633
634template <typename T>
636 : m_ptr(nullptr)
637{
638}
639
640template <typename T>
642 : m_ptr(ptr)
643{
644 Acquire();
645}
646
647template <typename T>
648Ptr<T>::Ptr(T* ptr, bool ref)
649 : m_ptr(ptr)
650{
651 if (ref)
652 {
653 Acquire();
654 }
655}
656
657template <typename T>
659 : m_ptr(nullptr)
660{
661 T* ptr = PeekPointer(o);
662 if (ptr != nullptr)
663 {
664 m_ptr = ptr;
665 Acquire();
666 }
667}
668
669template <typename T>
670template <typename U>
672 : m_ptr(PeekPointer(o))
673{
674 Acquire();
675}
676
677template <typename T>
679{
680 if (m_ptr != nullptr)
681 {
682 m_ptr->Unref();
683 }
684}
685
686template <typename T>
687Ptr<T>&
689{
690 if (&o == this)
691 {
692 return *this;
693 }
694 if (m_ptr != nullptr)
695 {
696 m_ptr->Unref();
697 }
698 m_ptr = o.m_ptr;
699 Acquire();
700 return *this;
701}
702
703template <typename T>
704T*
706{
707 NS_ASSERT_MSG(m_ptr, "Attempted to dereference zero pointer");
708 return m_ptr;
709}
710
711template <typename T>
712T*
714{
715 NS_ASSERT_MSG(m_ptr, "Attempted to dereference zero pointer");
716 return m_ptr;
717}
718
719template <typename T>
720T&
722{
723 NS_ASSERT_MSG(m_ptr, "Attempted to dereference zero pointer");
724 return *m_ptr;
725}
726
727template <typename T>
728T&
730{
731 NS_ASSERT_MSG(m_ptr, "Attempted to dereference zero pointer");
732 return *m_ptr;
733}
734
735template <typename T>
737{
738 return m_ptr != nullptr;
739}
740
741} // namespace ns3
742
743/****************************************************
744 * Global Functions (outside namespace ns3)
745 ***************************************************/
746
747/**
748 * \ingroup ptr
749 * Hashing functor taking a `Ptr` and returning a @c std::size_t.
750 * For use with `unordered_map` and `unordered_set`.
751 *
752 * \note When a `Ptr` is used in a container the lifetime of the underlying
753 * object is at least as long as the container. In other words,
754 * you need to remove the object from the container when you are done with
755 * it, otherwise the object will persist until the container itself is
756 * deleted.
757 *
758 * \tparam T \deduced The type held by the `Ptr`
759 */
760template <class T>
761struct std::hash<ns3::Ptr<T>>
762{
763 /**
764 * The functor.
765 * \param p The `Ptr` value to hash.
766 * \return the hash
767 */
768 std::size_t operator()(ns3::Ptr<T> p) const
769 {
770 return std::hash<const T*>()(ns3::PeekPointer(p));
771 }
772};
773
774#endif /* PTR_H */
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
Smart pointer class similar to boost::intrusive_ptr.
Ptr(T *ptr)
Create a smart pointer which points to the object pointed to by the input raw pointer ptr.
Definition ptr.h:641
Ptr(const Ptr &o)
Copy by referencing the same underlying object.
Definition ptr.h:658
T & operator*()
A dereference.
Definition ptr.h:729
Ptr()
Create an empty smart pointer.
Definition ptr.h:635
void Acquire() const
Mark this as a a reference by incrementing the reference count.
Definition ptr.h:626
friend U * PeekPointer(const Ptr< U > &p)
Get a temporary pointer to the underlying object.
Definition ptr.h:443
Ptr(const Ptr< U > &o)
Copy, removing const qualifier.
Definition ptr.h:671
T * operator->()
An lvalue member access.
Definition ptr.h:705
T & operator*() const
A const dereference.
Definition ptr.h:721
friend U * GetPointer(const Ptr< U > &p)
Get a permanent pointer to the underlying object.
Definition ptr.h:450
Ptr< T > & operator=(const Ptr &o)
Assignment operator by referencing the same underlying object.
Definition ptr.h:688
Ptr(T *ptr, bool ref)
Create a smart pointer which points to the object pointed to by the input raw pointer ptr.
Definition ptr.h:648
~Ptr()
Destructor.
Definition ptr.h:678
T * m_ptr
The pointer.
Definition ptr.h:69
T * operator->() const
An rvalue member access.
Definition ptr.h:713
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
bool operator>=(const int64x64_t &lhs, const int64x64_t &rhs)
Greater or equal operator.
Definition int64x64.h:162
bool operator<=(const int64x64_t &lhs, const int64x64_t &rhs)
Less or equal operator.
Definition int64x64.h:149
bool operator>(const Length &left, const Length &right)
Check if left has a value greater than right.
Definition length.cc:410
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
bool operator!=(Callback< R, Args... > a, Callback< R, Args... > b)
Inequality test.
Definition callback.h:658
bool operator==(const EventId &a, const EventId &b)
Definition event-id.h:155
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
Ptr< T1 > const_pointer_cast(const Ptr< T2 > &p)
Return a copy of p with its stored pointer const casted from T2 to T1.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
bool operator<(const EventId &a, const EventId &b)
Definition event-id.h:168
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition ptr.h:604
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
U * GetPointer(const Ptr< U > &p)
Definition ptr.h:450
Ptr< T1 > ConstCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:573
static T & GetReference(const Ptr< T > p)
Definition ptr.h:387
Helper for the MakeEvent functions which take a class method.
Definition ptr.h:400
std::size_t operator()(ns3::Ptr< T > p) const
The functor.
Definition ptr.h:768