Coverage Report

Created: 2026-05-04 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/Fast-DDS/src/cpp/utils/RefCountedPointer.hpp
Line
Count
Source
1
// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
 * @file RefCountedPointer.hpp
17
 */
18
19
#ifndef UTILS__REFCOUNTEDPOINTER_HPP
20
#define UTILS__REFCOUNTEDPOINTER_HPP
21
22
#include <atomic>
23
#include <cassert>
24
#include <condition_variable>
25
#include <cstdint>
26
#include <memory>
27
#include <mutex>
28
29
namespace eprosima {
30
namespace fastdds {
31
32
/**
33
 * @brief Class to manage a local pointer with reference counting.
34
 *
35
 * It is similar to std::shared_ptr, but designed for cases where
36
 * a shared pointer cannot be used due to API restrictions.
37
 *
38
 * USAGE:
39
 * - On T class:
40
 *   - Add a shared_ptr<RefCountedPointer<T>> local_ptr_ member.
41
 *   - Call local_ptr_->deactivate() before destroying T.
42
 *
43
 * - On classes that need to use a pointer to T:
44
 *   - Keep a copy of the shared_ptr<RefCountedPointer<T>>.
45
 *   - Whenever you need to access T:
46
 *     RefCountedPointer<T>::Instance instance(local_ptr_)
47
 *     if (instance)
48
 *     {
49
 *         ptr->method();
50
 *     }
51
 */
52
template<typename T>
53
class RefCountedPointer
54
{
55
public:
56
57
    class Instance;
58
59
    /**
60
     * @brief Explicit constructor.
61
     * @param ptr Pointer to manage.
62
     *
63
     * @pre nullptr != ptr. We must ensure that the pointer we
64
     * are manaing is valid.
65
     */
66
    explicit RefCountedPointer(
67
            T* ptr)
68
0
        : ptr_(ptr)
69
0
        , is_active_(true)
70
0
        , instances_(0)
71
0
    {
72
0
        assert(nullptr != ptr);
73
0
    }
74
75
0
    ~RefCountedPointer() = default;
76
77
    // Non-copyable and non-movable
78
    RefCountedPointer(
79
            const RefCountedPointer&) = delete;
80
    RefCountedPointer& operator =(
81
            const RefCountedPointer&) = delete;
82
    RefCountedPointer(
83
            RefCountedPointer&&) = delete;
84
    RefCountedPointer& operator =(
85
            RefCountedPointer&&) = delete;
86
87
    /**
88
     * @brief Class to manage the local pointer instance.
89
     * It will increase the reference count on construction and decrease
90
     * it on destruction. Provides a facade to access the pointee.
91
     */
92
    class Instance
93
    {
94
    public:
95
96
        /**
97
         * @brief Constructor.
98
         * @param parent Shared pointer reference to its RefCountedPointer.
99
         */
100
        explicit Instance(
101
                const std::shared_ptr<RefCountedPointer<T>>& parent)
102
0
            : parent_(parent)
103
0
            , ptr_(parent && parent->is_active_ ? parent->ptr_ : nullptr)
104
0
        {
105
0
            if (parent_)
106
0
            {
107
0
                parent_->inc_instances();
108
0
            }
109
0
        }
110
111
        /**
112
         * @brief Destructor.
113
         */
114
        ~Instance()
115
0
        {
116
0
            if (parent_)
117
0
            {
118
0
                parent_->dec_instances();
119
0
            }
120
0
        }
121
122
        // Non-copyable, default movable
123
        Instance(
124
                const Instance&) = delete;
125
        Instance& operator =(
126
                const Instance&) = delete;
127
        Instance(
128
                Instance&&) = default;
129
        Instance& operator =(
130
                Instance&&) = default;
131
132
        /**
133
         * @brief operator to check if the pointer is valid.
134
         */
135
        operator bool() const
136
0
        {
137
0
            return nullptr != ptr_;
138
0
        }
139
140
        /**
141
         * @brief operator to call the T methods.
142
         */
143
        T* operator ->() const
144
0
        {
145
0
            assert(nullptr != ptr_);
146
0
            return ptr_;
147
0
        }
148
149
    private:
150
151
        std::shared_ptr<RefCountedPointer<T>> parent_;
152
        T* const ptr_;
153
    };
154
155
    /**
156
     * @brief Ensure no more valid local pointer instances are created, and wait for current ones to die.
157
     */
158
    void deactivate()
159
0
    {
160
0
        std::unique_lock<std::mutex> lock(mutex_);
161
0
        is_active_ = false;
162
0
        cv_.wait(lock, [this]() -> bool
163
0
                {
164
0
                    return instances_ == 0;
165
0
                });
166
0
    }
167
168
private:
169
170
    /**
171
     * @brief Increase the reference count.
172
     */
173
    void inc_instances()
174
0
    {
175
0
        std::unique_lock<std::mutex> lock(mutex_);
176
0
        ++instances_;
177
0
    }
178
179
    /**
180
     * @brief Decrease the reference count.
181
     */
182
    void dec_instances()
183
0
    {
184
0
        std::unique_lock<std::mutex> lock(mutex_);
185
0
        --instances_;
186
0
        if (instances_ == 0)
187
0
        {
188
0
            cv_.notify_one();
189
0
        }
190
0
    }
191
192
    /**
193
     * Pointer to the managed object.
194
     */
195
    T* const ptr_;
196
197
    /**
198
     * Indicates whether the pointee is still alive
199
     * and accessing the pointer is valid.
200
     */
201
    std::atomic<bool> is_active_;
202
203
    /**
204
     * Protections for the number of instances.
205
     */
206
    mutable std::mutex mutex_;
207
    std::condition_variable cv_;
208
209
    /**
210
     * Number of active instances (currently using the pointee).
211
     */
212
    size_t instances_;
213
};
214
215
}  // namespace fastdds
216
}  // namespace eprosima
217
218
#endif // UTILS__REFCOUNTEDPOINTER_HPP