Line data Source code
1 : // Copyright (c) 2019-2026 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdev
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 : #pragma once
19 :
20 : /** \file
21 : * \brief Implementation of a safe object template.
22 : *
23 : * Once in a while, an object (such as a C resource) is created and it is
24 : * a bare pointer for some time. This template allows you to make sure that
25 : * the object will either be deleted (i.e. if an exception or early return
26 : * happens) or safely saved in a place where it will be remembered properly.
27 : *
28 : * You want to supply the bare pointer type, the pointer itself, and when
29 : * required a deleter. By default, the deleter is simply uses the delete
30 : * operator.
31 : *
32 : * The main difference with this safe_object template, compared to using
33 : * a smart pointer, is that you have the ability to safely take the pointer
34 : * out of the safe_object with the release() function. After that one
35 : * call, the object pointer is set to nullptr and thus the safe_object
36 : * will not release it.
37 : *
38 : * \code
39 : * {
40 : * snapdev::safe_object<my_type *> so; // create the safe object first
41 : * my_type * obj(new my_type); // create your object
42 : * so.make_safe(obj); // make it safe for a while
43 : *
44 : * ...your statements while obj isn't safe...
45 : *
46 : * // if an interrupt happened before this statement, then obj
47 : * // was safely deleted
48 : * //
49 : * so.release();
50 : * }
51 : * \endcode
52 : *
53 : * You should not try to use the `safe_object<>` template as a replacement
54 : * of the `shared_ptr<>` template. It is not the same. You cannot
55 : * copy a `safe_object<>`.
56 : */
57 :
58 : namespace snapdev
59 : {
60 :
61 : namespace detail
62 : {
63 :
64 :
65 :
66 : template<typename T>
67 6 : void default_safe_object_deleter(T ptr)
68 : {
69 6 : delete ptr;
70 6 : }
71 :
72 :
73 :
74 : } // namespace detail
75 :
76 :
77 : /** \brief Make a pointer of a given type safe.
78 : *
79 : * This class is used to make a variable safe. This is important if you
80 : * allocate a resource, do further initialization that can throw, and then
81 : * safe the resource pointer as required.
82 : *
83 : * This is particularly useful if you need to allocate multiple objects
84 : * in a row and need to save pointers until all can safely be saved in a
85 : * final destination.
86 : *
87 : * To handle a bare pointer, make sure to pass that as the type T.
88 : *
89 : * \tparam T The type of the value to save and restore.
90 : * \tparam deleter A function called when the object needs to be deleted.
91 : */
92 : template<typename T, void(deleter)(T) = detail::default_safe_object_deleter>
93 : class safe_object
94 : {
95 : public:
96 : /** \brief Create a safe_object on your stack.
97 : *
98 : * This object is expected to be created on your stack.
99 : *
100 : * An object of this type cannot be copied. It is expected to only be
101 : * used on the stack so it goes out of scope at the next `}`.
102 : *
103 : * \note
104 : * For that reason the copy and assignment operators are deleted.
105 : */
106 22 : safe_object()
107 22 : {
108 22 : }
109 :
110 : /** \brief Prevent copying safe_object's.
111 : *
112 : * Delete the copy operator so you can't copy these objects. There is not
113 : * reference counter or similar feature so we need to make sure you
114 : * cannot copy (like unique_ptr) or transfer (like auto_ptr) ownership.
115 : */
116 : safe_object(safe_object const &) = delete;
117 :
118 : /** \brief Prevent assignment of safe_object's.
119 : *
120 : * Delete the assignment operator so you can't copy these objects. There
121 : * is not reference counter or similar feature so we need to make sure you
122 : * cannot copy (like unique_ptr) or transfer (like auto_ptr) ownership.
123 : */
124 : safe_object & operator = (safe_object const &) = delete;
125 :
126 : /** \brief Delete the value is not yet released.
127 : *
128 : * On destruction, the value gets deleted by the defaulr ot user
129 : * specified deleter.
130 : */
131 22 : ~safe_object()
132 : {
133 22 : cleanup();
134 22 : }
135 :
136 : /** \brief Update the value through the safe object.
137 : *
138 : * This function allows you to update the value. Since you are
139 : * expected to have direct access to the variable saved in this
140 : * object, it is likely not very useful to call this function.
141 : * It is here primarily for completeness.
142 : *
143 : * \warning
144 : * This function calls the cleanup() function to make sure that
145 : * if a previous object was present, it gets deleted.
146 : *
147 : * \param[in] object The object to protect from exceptions.
148 : */
149 22 : void make_safe(T object)
150 : {
151 22 : if(object != f_object)
152 : {
153 22 : cleanup();
154 22 : f_released = false;
155 22 : f_object = object;
156 : }
157 22 : }
158 :
159 : /** \brief Release the value.
160 : *
161 : * This function releases the value, which means the deleter will
162 : * not be called against it.
163 : *
164 : * This or another object can be re-added by calling the
165 : * make_safe() function again.
166 : */
167 11 : void release()
168 : {
169 11 : f_released = true;
170 11 : }
171 :
172 : /** \brief Get a reference to the saved value.
173 : *
174 : * This function returns a reference to the saved value. Since it
175 : * is a constant, returning a reference is safe even in a
176 : * multi-threaded environment.
177 : *
178 : * If you used the constructor with a `restore` parameter, then that
179 : * value is returned by this function.
180 : *
181 : * \note
182 : * It is not possible to change the saved value.
183 : *
184 : * \return The protected object.
185 : */
186 : T protected_object() const
187 : {
188 : return f_object;
189 : }
190 :
191 : /** \brief Clean up the object if not yet released.
192 : *
193 : * This function makes sure to call the deleter on the currently
194 : * protected object, contrary to the release() function which
195 : * makes sure not to call the deleter.
196 : */
197 44 : void cleanup()
198 : {
199 44 : if(!f_released)
200 : {
201 11 : f_released = true;
202 11 : deleter(f_object);
203 : }
204 44 : }
205 :
206 : private:
207 : /** \brief The object to protect.
208 : *
209 : * This field is the object to protect. In most cases, this is going
210 : * to be a pointer. It could very well be an identifier or another type
211 : * of resource handle.
212 : */
213 : T f_object = T();
214 :
215 : /** \brief Whether the value was released or not.
216 : *
217 : * This value tells us whether the release() function was called (true)
218 : * or not (false).
219 : *
220 : * When this field is `true` the deleter is not called against
221 : * f_object. By default, this value is true.
222 : */
223 : bool f_released = true;
224 : };
225 :
226 :
227 :
228 : } // namespace snapdev
229 : // vim: ts=4 sw=4 et
|