Skip to content

Commit e072c7b

Browse files
author
jparisu
committed
Refs #15831: Add doxygen to fragile_ptr
Signed-off-by: jparisu <[email protected]>
1 parent 25c7c58 commit e072c7b

File tree

1 file changed

+97
-52
lines changed

1 file changed

+97
-52
lines changed

src/cpp/types/fragile_ptr.hpp

Lines changed: 97 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
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 {
3029
namespace 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
*/
3551
template <typename T>
3652
class 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

188222
protected:
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.
243288
template <typename T>
244289
std::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

Comments
 (0)