GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/smart_pointer.h
Date: 2026-09-07 02:28:19
Exec Total Coverage
Lines: 24 27 88.9%
Functions: 32 53 60.4%
Branches: 93 219 42.5%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef GEOGRAM_BASIC_SMART_POINTER
41 #define GEOGRAM_BASIC_SMART_POINTER
42
43 #include <geogram/basic/common.h>
44 #include <geogram/basic/assert.h>
45 #include <geogram/basic/memory.h>
46
47 /**
48 * \file geogram/basic/smart_pointer.h
49 * \brief Pointers with automatic reference counting
50 */
51
52 namespace GEO {
53
54 /************************************************************************/
55
56 /**
57 * \brief A smart pointer with reference-counted copy semantics.
58 *
59 * \tparam T the type of pointers stored in the SmartPointer.
60 * \details
61 * SmartPointer%s have the ability of taking ownership of a pointer of
62 * type \p T and share that ownership: once they take ownership, the group
63 * of owners of a pointer become responsible for its deletion when the
64 * last one of them releases that ownership.
65 *
66 * The object pointed to must implement the two following static
67 * functions:
68 * - T::ref(T*): to increment the reference count
69 * - T::unref(T*): to decrement the reference count.
70 *
71 * More specifically, SmartPointer can be used with classes inheriting the
72 * Counted class.
73 * \see Counted
74 */
75 template <class T>
76 class SmartPointer {
77 public:
78 /**
79 * \brief Creates an empty smart pointer
80 */
81 7378 SmartPointer() :
82
7/16
✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 39 times.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
5260 pointer_(nullptr) {
83 }
84
85 /**
86 * \brief Creates a smart pointer that owns a pointer
87 * \details This calls T::ref() on the pointer \p ptr to take
88 * ownership on it.
89 * \param[in] ptr source pointer convertible to T*
90 */
91 13881 SmartPointer(T* ptr) :
92
24/43
✓ Branch 0 taken 1269 times.
✓ Branch 1 taken 645 times.
✓ Branch 2 taken 553 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 473 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 473 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 36 times.
✓ Branch 10 taken 473 times.
✓ Branch 11 taken 36 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 473 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 473 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 473 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 473 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 473 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 473 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 473 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 473 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 473 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 473 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 178 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 509 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 1952 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 640 times.
✗ Branch 53 not taken.
✓ Branch 55 taken 1911 times.
✗ Branch 56 not taken.
13881 pointer_(ptr) {
93 T::ref(pointer_);
94 }
95
96 /**
97 * \brief Create a copy of a smart pointer
98 * \details This calls T::ref() on the pointer help by \p rhs to take
99 * ownership on it.
100 * \param[in] rhs the smart pointer to copy
101 */
102 32568 SmartPointer(const SmartPointer<T>& rhs) :
103
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
32568 pointer_(rhs) {
104 T::ref(pointer_);
105 }
106
107 /**
108 * \brief Deletes a smart pointer
109 * \details This calls T::unref() to release ownership on the help
110 * pointer. If this smart pointer is the last one owning the pointer,
111 * the pointer is deleted.
112 */
113 1260 ~SmartPointer() {
114
9/28
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 3095 times.
✓ Branch 2 taken 5690 times.
✓ Branch 3 taken 51 times.
✓ Branch 4 taken 9368 times.
✓ Branch 5 taken 257 times.
✓ Branch 6 taken 12844 times.
✓ Branch 7 taken 25 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 7 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
31404 T::unref(pointer_);
115
22/38
✓ Branch 0 taken 505 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 514 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 473 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 473 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 473 times.
✓ Branch 9 taken 35 times.
✓ Branch 10 taken 473 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 473 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 473 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 473 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 473 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 473 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 473 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 473 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 473 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 178 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 509 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 1952 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 640 times.
✗ Branch 35 not taken.
✓ Branch 36 taken 1911 times.
✗ Branch 37 not taken.
42196 }
116
117 /**
118 * \brief Assignment from a pointer
119 * \details Releases ownership on the stored pointer as if reset()
120 * were called and takes ownership on \p ptr.
121 * \param[in] ptr a pointer convertible to T*
122 * \return this smart pointer
123 */
124 12273 SmartPointer<T>& operator= (T* ptr) {
125
2/4
✓ Branch 0 taken 6731 times.
✓ Branch 1 taken 1757 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12273 if(ptr != pointer_) {
126 T::unref(pointer_);
127
2/2
✓ Branch 0 taken 6480 times.
✓ Branch 1 taken 251 times.
8759 pointer_ = ptr;
128 T::ref(pointer_);
129 }
130 12273 return *this;
131 }
132
133 /**
134 * \brief Assignment from a smart pointer
135 * \details Releases ownership on the stored pointer as if reset()
136 * were called and takes ownership on the pointer stored in \p rhs.
137 * \param[in] rhs the smart pointer to copy
138 * \return this smart pointer
139 */
140 300 SmartPointer<T>& operator= (const SmartPointer<T>& rhs) {
141 T* rhs_p = rhs.get();
142 300 if(rhs_p != pointer_) {
143 T::unref(pointer_);
144 pointer_ = rhs_p;
145 T::ref(pointer_);
146 }
147 300 return *this;
148 }
149
150 /**
151 * \brief Resets pointer
152 * \details Releases ownership on the help pointer and resets it to
153 * null. The smart pointer becomes as if it were default-constructed.
154 * \note P.reset() is equivalent to assigning
155 * a nullptr pointer: p = nullptr
156 */
157 void reset() {
158
2/2
✓ Branch 0 taken 1006 times.
✓ Branch 1 taken 12 times.
1018 T::unref(pointer_);
159
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
1018 pointer_ = nullptr;
160 }
161
162 /**
163 * \brief Dereferences object member
164 * \details Returns the stored pointer in order to access one of its
165 * members. This member function shall not be called if the stored
166 * pointer is a null pointer.
167 * \return the stored pointer if not null, or aborts otherwise.
168 */
169 1839974 T* operator-> () const {
170
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1804233 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1839974 geo_assert(pointer_ != nullptr);
171 1839974 return pointer_;
172 }
173
174 /**
175 * \brief Dereferences object
176 * \details Returns the stored pointer in order to dereference it.
177 * This member function shall not be called if the stored pointer is a
178 * null pointer.
179 * \return the stored pointer if not null, or aborts otherwise.
180 */
181 T& operator* () const {
182 geo_assert(pointer_ != nullptr);
183 return *pointer_;
184 }
185
186 /**
187 * \brief Conversion operator
188 * \return the stored pointer
189 */
190 operator T* () const {
191
12/26
✓ Branch 0 taken 14696 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10249 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3991 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2720 times.
✓ Branch 7 taken 24702 times.
✓ Branch 8 taken 23 times.
✓ Branch 9 taken 265 times.
✓ Branch 10 taken 4327 times.
✓ Branch 11 taken 8 times.
✓ Branch 12 taken 293 times.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 23935 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
97496 return pointer_;
192 }
193
194 /**
195 * \brief Get pointer
196 * \return the stored pointer
197 */
198 T* get() const {
199
3/32
✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
7795 return pointer_;
200 }
201
202 /**
203 * \brief Check if stored pointer is null
204 * \return \c true if the stored pointer is null, \c false otherwise.
205 */
206 bool is_null() const {
207
8/14
✓ Branch 0 taken 429666 times.
✓ Branch 1 taken 335 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2947458 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 209840 times.
✓ Branch 9 taken 81900 times.
✓ Branch 10 taken 786797 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
4456028 return pointer_ == nullptr;
208 }
209
210 private:
211 T* pointer_;
212 };
213
214 /**
215 * \brief Equal operator
216 * \param[in] lhs the first pointer to compare
217 * \param[in] rhs the second pointer to compare
218 * \return \c true if the pointer stored in \p lhs is equal to the pointer
219 * stored in \p rhs.
220 * \relates SmartPointer
221 */
222 template <class T1, class T2>
223 inline bool operator== (
224 const SmartPointer<T1>& lhs, const SmartPointer<T2>& rhs
225 ) {
226 return lhs.get() == rhs.get();
227 }
228
229 /**
230 * \brief Not equal operator
231 * \param[in] lhs the first pointer to compare
232 * \param[in] rhs the second pointer to compare
233 * \return \c true if the pointer stored in \p lhs is not equal to the
234 * pointer stored in \p rhs.
235 * \relates SmartPointer
236 */
237 template <class T1, class T2>
238 inline bool operator!= (
239 const SmartPointer<T1>& lhs, const SmartPointer<T2>& rhs
240 ) {
241 return lhs.get() != rhs.get();
242 }
243
244 /**
245 * \brief Less than operator
246 * \param[in] lhs the first pointer to compare
247 * \param[in] rhs the second pointer to compare
248 * \return \c true if the pointer stored in \p lhs is less than the
249 * pointer stored in \p rhs.
250 * \relates SmartPointer
251 */
252 template <class T1, class T2>
253 inline bool operator< (
254 const SmartPointer<T1>& lhs, const SmartPointer<T2>& rhs
255 ) {
256 return lhs.get() < rhs.get();
257 }
258
259 /**
260 * \brief Less or equal operator
261 * \param[in] lhs the first pointer to compare
262 * \param[in] rhs the second pointer to compare
263 * \return \c true if the pointer stored in \p lhs is less than or equal
264 * to the pointer stored in \p rhs.
265 * \relates SmartPointer
266 */
267 template <class T1, class T2>
268 inline bool operator<= (
269 const SmartPointer<T1>& lhs, const SmartPointer<T2>& rhs
270 ) {
271 return lhs.get() <= rhs.get();
272 }
273
274 /**
275 * \brief Greater than operator
276 * \param[in] lhs the first pointer to compare
277 * \param[in] rhs the second pointer to compare
278 * \return \c true if the pointer stored in \p lhs is greater than the
279 * pointer stored in \p rhs.
280 * \relates SmartPointer
281 */
282 template <class T1, class T2>
283 inline bool operator> (
284 const SmartPointer<T1>& lhs, const SmartPointer<T2>& rhs
285 ) {
286 return lhs.get() > rhs.get();
287 }
288
289 /**
290 * \brief Greater or equal operator
291 * \param[in] lhs the first pointer to compare
292 * \param[in] rhs the second pointer to compare
293 * \return \c true if the pointer stored in \p lhs is greater than or
294 * equal to the pointer stored in \p rhs.
295 * \relates SmartPointer
296 */
297 template <class T1, class T2>
298 inline bool operator>= (
299 const SmartPointer<T1>& lhs, const SmartPointer<T2>& rhs
300 ) {
301 return lhs.get() >= rhs.get();
302 }
303 }
304
305 #endif
306