1919#ifndef _EPROSIMA_FASTDDS_STATISTICS_BACKEND_TYPES_FRAGILEPTR_HPP_
2020#define _EPROSIMA_FASTDDS_STATISTICS_BACKEND_TYPES_FRAGILEPTR_HPP_
2121
22- #include < iostream> // TODO remove
2322#include < memory>
2423#include < type_traits>
2524
@@ -30,7 +29,24 @@ namespace statistics_backend {
3029namespace details {
3130
3231/* *
33- * TODO add comments
32+ * @brief This class represents a Smart Pointer that works as a \c weak_ptr but has the API of a \c shared_ptr .
33+ *
34+ * A \c fragile_ptr is a Smart Pointer that holds a weak reference to an object of kind \c T .
35+ * A weak reference implies that there is no assurance that this object will exit (will not be destroyed somewhere
36+ * else) all along the life of this object.
37+ * This class replicates the API of a shared_ptr and those times that the internal reference is used
38+ * (operator-> and operator*) it throws an exception if the internal reference has expired.
39+ *
40+ * @note This class may seen as dangerous one. But it is actually better than a shared_ptr, as shared does not
41+ * prevent you to do a operator-> of a nullptr, and this does.
42+ * @note This class may also seen as a useless one. I agree, but its main use is not to change the whole project
43+ * all around where shared_ptr was used before.
44+ *
45+ * @note This class has been used because internal entities of the database hold references to each other.
46+ * This implies loops between shared ptrs.
47+ * These references are supposed to not be destroyed as long as the entity (that holds them) lives, so
48+ * changing shared for fragile should not change the behaviour.
49+ * These shared_ptr has been replaced with fragile_ptr so code does not have to change everywhere.
3450 */
3551template <typename T>
3652class fragile_ptr
@@ -41,29 +57,47 @@ class fragile_ptr
4157 // ///////////////////
4258 // CONSTRUCTORS
4359
60+ // ! Default constructor to nullptr
4461 fragile_ptr () noexcept = default ;
4562
63+ // ! Default constructors and operator= from other \c fragile_ptr ( \c weak_ptr are copiable and moveable).
4664 fragile_ptr (const fragile_ptr<T>& copy_other) = default ;
4765 fragile_ptr (fragile_ptr<T>&& move_other) = default ;
4866 fragile_ptr& operator =(const fragile_ptr<T>& copy_other) = default ;
4967 fragile_ptr& operator =(fragile_ptr<T>&& move_other) = default ;
5068
51- ~fragile_ptr () = default ;
69+ // ! Default destructor
70+ virtual ~fragile_ptr () = default ;
5271
5372 // ///////////////////
5473 // CONSTRUCTORS FROM SHARED PTR
5574
75+ /* *
76+ * @brief Construct a new fragile ptr object from a shared one
77+ *
78+ * It initializes the internal \c weak_ptr with the reference of the shared one.
79+ *
80+ * @param shared_reference \c shared_ptr to the reference to point from this.
81+ */
5682 fragile_ptr (const std::shared_ptr<T>& shared_reference)
5783 : reference_(shared_reference)
5884 {
5985 // Do nothing
6086 }
6187
88+ // ! Same as calling basic constructor.
6289 fragile_ptr (std::nullptr_t )
6390 {
6491 // Do nothing
6592 }
6693
94+ /* *
95+ * @brief Construct a new fragile ptr object from a shared one
96+ *
97+ * It initializes the internal \c weak_ptr with the reference of the shared one.
98+ *
99+ * @param shared_reference \c shared_ptr to the reference to point from this.
100+ */
67101 fragile_ptr& operator =(const std::shared_ptr<T>& copy_other)
68102 {
69103 this ->reference_ = copy_other;
@@ -73,36 +107,30 @@ class fragile_ptr
73107 // ///////////////////
74108 // OPERATOR METHODS
75109
76- // template <typename U>
77- // bool operator==(const std::shared_ptr<T>& other) const noexcept
78- // {
79- // static_assert(std::is_base_of<U, T>::value, "U must inherit from T");
80- // return std::dynamic_pointer_cast<U>(this->safety_lock_()) == other;
81- // }
82-
83- // TODO: use if_enabled or somehow limit this cast to only those U that are coherent
110+ /* *
111+ * @brief Compare this ptr reference with a shared one.
112+ *
113+ * @todo use if_enabled or somehow limit this cast to only those U that are coherent
114+ */
84115 template <typename U>
85116 bool operator ==(const std::shared_ptr<U>& other) const noexcept
86117 {
87118 static_assert (std::is_base_of<U, T>::value, " U must inherit from T" );
88- if (other == nullptr )
89- {
90- return this ->expired ();
91- }
92- else
93- {
94- return this ->safety_lock_ () == other;
95- }
119+ return this ->lock () == other;
96120 }
97121
98122 // ///////////////////
99123 // CAST METHODS
100124
101- // TODO: use if_enabled or somehow limit this cast to only those U that are coherent
125+ /* *
126+ * @brief Cast this object to a \c shared_ptr object of type \c U .
127+ *
128+ * @todo use if_enabled or somehow limit this cast to only those U that are coherent
129+ */
102130 template <typename U>
103131 operator std::shared_ptr<U> () const
104132 {
105- auto cast_result = std::dynamic_pointer_cast<U>(safety_lock_ ());
133+ auto cast_result = std::dynamic_pointer_cast<U>(this -> lock ());
106134 if (!cast_result)
107135 {
108136 // TODO: show in error message the name of the types that are being casted
@@ -114,54 +142,34 @@ class fragile_ptr
114142 }
115143 }
116144
117- // TODO: implement it somehow
118- // template <typename U>
119- // operator
120- // typename std::enable_if<std::true_type::value, std::shared_ptr<U>>::type () const
121- // {
122- // auto cast_result = std::dynamic_pointer_cast<U>(safety_lock_());
123- // if (!cast_result)
124- // {
125- // // TODO: show in error message the name of the types that are being casted
126- // throw Inconsistency("Trying to cast to a not valid object.");
127- // }
128- // else
129- // {
130- // return cast_result;
131- // }
132- // }
133-
145+ // ! Cast this object to a \c shared_ptr of the same type.
134146 operator std::shared_ptr<T>() const
135147 {
136- return safety_lock_ ();
148+ return this -> lock ();
137149 }
138150
151+ // ! Wether the internal ptr is valid (it it has been initialized and it has expired).
139152 operator bool () const noexcept
140153 {
141154 return !reference_.expired ();
142155 }
143156
144- // ///////////////////
145- // INTERACTION METHODS
146-
147- std::shared_ptr<T> get_shared_ptr () const
148- {
149- return safety_lock_ ();
150- }
151-
152157 // ///////////////////
153158 // WEAK PTR METHODS
154159
160+ // ! \c weak_ptr::expired call.
155161 bool expired () const noexcept
156162 {
157163 return reference_.expired ();
158164 }
159165
166+ // ! \c weak_ptr::lock call.
160167 std::shared_ptr<T> lock () const noexcept
161168 {
162169 return reference_.lock ();
163170 }
164171
172+ // ! \c weak_ptr::reset call.
165173 void reset () noexcept
166174 {
167175 reference_.reset ();
@@ -170,23 +178,58 @@ class fragile_ptr
170178 // ///////////////////
171179 // SHARED PTR METHODS
172180
173- T* operator ->() const
181+ /* *
182+ * @brief Get the internal reference.
183+ *
184+ * @warning The internal reference is not protected. Thus, it could be removed from other thread while using
185+ * it even if this object still exist. Use \c lock instead for a protected use of the internal value.
186+ *
187+ * @return T* internal reference (could be null)
188+ */
189+ T* get () const
174190 {
175- return safety_lock_ ().operator -> ();
191+ return lock ().get ();
176192 }
177193
178- T* get () const
194+ /* *
195+ * @brief Get the internal reference by -> operator.
196+ *
197+ * @warning The internal reference is not protected. Thus, it could be removed from other thread while using
198+ * it even if this object still exist. Use \c lock instead for a protected use of the internal value.
199+ *
200+ * @return T* internal reference if not expired.
201+ * @throw \c Inconsistency if the internal reference is not valid.
202+ */
203+ T* operator ->() const
179204 {
180- return safety_lock_ ().get ();
205+ return safety_lock_ ().operator -> ();
181206 }
182207
208+ /* *
209+ * @brief Get the internal reference by * operator.
210+ *
211+ * @warning The internal reference is not protected. Thus, it could be removed from other thread while using
212+ * it even if this object still exist. Use \c lock instead for a protected use of the internal value.
213+ *
214+ * @return T& internal reference if not expired.
215+ * @throw \c Inconsistency if the internal reference is not valid.
216+ */
183217 T& operator *() const
184218 {
185219 return safety_lock_ ().operator *();
186220 }
187221
188222protected:
189223
224+ /* *
225+ * @brief This method calls \c weak_ptr::lock . In case the reference is not valid anymore
226+ * it throws an exception to warn about its usage.
227+ *
228+ * It uses for those cases where using the internal reference must be protected by an exception call in error case.
229+ *
230+ * @return return of shared_ptr result from lock
231+ * @throw \c Inconsistency if the internal reference is not valid.
232+ */
190233 std::shared_ptr<T> safety_lock_ () const
191234 {
192235 auto lock_reference = reference_.lock ();
@@ -200,6 +243,7 @@ class fragile_ptr
200243 }
201244 }
202245
246+ // ! Internal weak reference to a ptr.
203247 std::weak_ptr<T> reference_;
204248
205249};
@@ -240,6 +284,7 @@ bool operator !=(
240284 return nullptr != lhs.lock ();
241285}
242286
287+ // ! Serialize operator giving the address of the internal reference, or nullptr if not valid.
243288template <typename T>
244289std::ostream& operator <<(
245290 std::ostream& o,
@@ -251,7 +296,7 @@ std::ostream& operator <<(
251296 }
252297 else
253298 {
254- o << f. lock () ;
299+ o << " { " << f. get () << " } " ;
255300 }
256301 return o;
257302}
0 commit comments