c++-gtk-utils: shared_handle.h Source File

c++-gtk-utils

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

shared_handle.h
Go to the documentation of this file.
1 /* Copyright (C) 2004 to 2019 Chris Vine
2
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public License
9 as published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License, version 2.1, for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License, version 2.1, along with this library (see the file LGPL.TXT
19 which came with this source code package in the c++-gtk-utils
20 sub-directory); if not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23 However, it is not intended that the object code of a program whose
24 source code instantiates a template from this file or uses macros or
25 inline functions (of any length) should by reason only of that
26 instantiation or use be subject to the restrictions of use in the GNU
27 Lesser General Public License. With that in mind, the words "and
28 macros, inline functions and instantiations of templates (of any
29 length)" shall be treated as substituted for the words "and small
30 macros and small inline functions (ten lines or less in length)" in
31 the fourth paragraph of section 5 of that licence. This does not
32 affect any other reason why object code may be subject to the
33 restrictions in that licence (nor for the avoidance of doubt does it
34 affect the application of section 2 of that licence to modifications
35 of the source code in this file).
36
37 */
38
39 #ifndef CGU_SHARED_HANDLE_H
40 #define CGU_SHARED_HANDLE_H
41
42 // define this if, instead of GLIB atomic funcions/memory barriers,
43 // you want to use a (slower) mutex to lock the reference count in the
44 // SharedLockHandle class
45 /* #define CGU_SHARED_LOCK_HANDLE_USE_MUTEX 1 */
46
47 #include <exception>
48 #include <new>
49 #include <functional> // for std::less and std::hash<T*>
50 #include <utility> // for std::swap
51 #include <cstddef> // for std::size_t
52 #include <cstdlib>
53
54 #include <glib.h>
55
56 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
57 #include <c++-gtk-utils/mutex.h>
58 #endif
59
60 #include <c++-gtk-utils/cgu_config.h>
61
62 /**
63 * @addtogroup handles handles and smart pointers
64 */
65
66 namespace Cgu {
67
68 /**
69 * @class SharedHandle shared_handle.h c++-gtk-utils/shared_handle.h
70 * @brief This is a generic class for managing the lifetime of objects
71 * allocated on freestore.
72 * @ingroup handles
73 * @sa SharedLockHandle
74 * @sa ScopedHandle
75 * @sa SharedHandleError
76 * @sa GcharSharedHandle
77 * @sa GerrorSharedHandle
78 * @sa StandardArrayDelete CFree GFree GerrorFree GSliceFree GSliceFreeSize GSliceDestroy
79 *
80 * The SharedHandle class is similar to the SharedPtr class (it keeps
81 * a reference count and deletes the handled object when the count
82 * reaches 0), but it does not have pointer semantics. Accordingly,
83 * it can be used to manage the memory of arrays and other objects
84 * allocated on the heap.
85 *
86 * Because it is useful with arrays, by default it deallocates memory
87 * using C++ delete[]. However, if a SharedHandle object is passed a
88 * function object type as a second template argument when
89 * instantiated, it will use that function object to delete memory.
90 * This enables it to handle the memory of any object, such as objects
91 * to be deleted using std::free() or Glib's g_free(), g_list_free()
92 * or g_slice_free(). Instances (such as @ref GcharScopedHandleAnchor
93 * "GcharScopedHandle", @ref GcharSharedHandleAnchor
94 * "GcharSharedHandle", @ref GerrorSharedHandleAnchor
95 * "GerrorSharedHandle" and @ref GerrorScopedHandleAnchor
96 * "GerrorScopedHandle") typdef'ed for particular deleters can
97 * conveniently manage objects of any kind.
98 *
99 * To reflect the fact that it is just a handle for a pointer, it has
100 * different instantiation semantics from a SharedPtr object. A
101 * SharedPtr object is instantiated using this syntax:
102 *
103 * @code SharedPtr<ObjType> sh_ptr(new ObjType); @endcode
104 *
105 * A SharedHandle is instantiated using this syntax (note that the
106 * instantiated handle is for type T* and not T):
107 *
108 * @code SharedHandle<ObjType*> sh_handle(new ObjType[n]); @endcode
109 *
110 *
111 * Apart from the operatorT() type conversion operator (which returns
112 * the underlying pointer), the only other method to obtain the
113 * underlying pointer is the get() method. If the object referenced
114 * is an array allocated on the heap, to use indexing you could either
115 * do this:
116 *
117 * @code
118 * using namespace Cgu;
119 * SharedHandle<char*> handle(new char[10]);
120 * handle.get()[0] = 'a';
121 * std::cout << handle.get()[0] << std::endl;
122 * @endcode
123 *
124 * or this:
125 *
126 * @code
127 * using namespace Cgu;
128 * SharedHandle<char*> handle(new char[10]);
129 * handle[0] = 'a';
130 * std::cout << handle[0] << std::endl;
131 * @endcode
132 *
133 * There is also a SharedLockHandle class, which has a thread-safe
134 * reference count, and a ScopedHandle class, which deletes its object
135 * as soon as it goes out of scope. A ScopedHandle class can be
136 * viewed as a SharedHandle which cannot be assigned to or used as the
137 * argument to a copy constructor and therefore which cannot have a
138 * reference count of more than 1. It is used where, if you wanted
139 * pointer semantics, you might use a const std::auto_ptr<>.
140 *
141 * SharedHandle objects can be instantiated for pointers to constant
142 * objects (such as SharedHandle<const char*>), provided the deleter
143 * functor will take such pointers.
144 *
145 * This library provides StandardArrayDelete, CFree, GFree,
146 * GerrorFree, GSliceFree, GSliceFreeSize and GSliceDestroy deleter
147 * functors, which can be used as the second template parameter of the
148 * SharedHandle class. As mentioned above, StandardArrayDelete is the
149 * default, and some typedef'ed instances of SharedHandle for gchar
150 * (with the GFree deleter) and for GError (with the GerrorFree
151 * deleter) are provided.
152 *
153 * @b Comparison @b with @b std::shared_ptr
154 *
155 * Although the semantics of std::shared_ptr in C++11/14 are not
156 * particularly suited to managing either arrays or C objects with
157 * accessor functions (such as in glib), most of the things that can
158 * be done by this class can be done by using std::shared_ptr with a
159 * specialised deleter. However, this class is retained in the
160 * c++-gtk-utils library not only to retain compatibility with series
161 * 1.2 of the library, but also to cater for some cases not met (or
162 * not so easily met) by std::shared_ptr:
163 *
164 * 1. The Cgu::SharedHandle class takes its deleter as a template
165 * parameter, which means that typedefs can be used to enable
166 * handles for particular deleters to be easily created (and as
167 * mentioned, this library provides a number of pre-formed deleter
168 * functors and typedefs for them). With std::shared_ptr, custom
169 * deleters must be passed to the shared_ptr constructor on every
170 * occasion a shared_ptr is constructed to manage a new object (and
171 * they cannot be templated as a typedef).
172 * 2. Glib memory slices provide an efficient small object allocator
173 * (they are likely to be significantly more efficient than global
174 * operator new()/new[](), which generally hand off to malloc(),
175 * and whilst malloc() is good for large block allocations it is
176 * generally poor as a small object allocator). Internal
177 * Cgu::SharedHandle allocation using glib memory slices can be
178 * achieved by compiling the library with the
179 * \--with-glib-memory-slices-no-compat configuration option.
180 * 3. If glib memory slices are not used (which do not throw),
181 * constructing a shared pointer for a new managed object (or
182 * calling reset() for a new managed object) might throw if
183 * internal allocation fails. Although by default the
184 * Cgu::SharedHandle implementation will delete the new managed
185 * object in such a case, it also provides an alternative
186 * constructor and reset() method which instead enable the new
187 * object to be accessed via the thrown exception object so that
188 * user code can decide what to do; std::shared_ptr deletes the new
189 * object in every case.
190 * 4. A user can explicitly state whether the shared handle object is
191 * to have atomic increment and decrement-and-test with respect to
192 * the reference count so that the reference count is thread safe
193 * ('no' in the case of Cgu::SharedHandle, and 'yes' in the case of
194 * Cgu::SharedLockHandle). Using atomic functions is unnecessary
195 * if the managed object concerned is only addressed in one thread
196 * (and might cause unwanted cache flushing in certain
197 * circumstances). std::shared_ptr will generally always use
198 * atomic functions with respect to its reference count in a
199 * multi-threaded program.
200 *
201 * In favour of std::shared_ptr, it has an associated std::weak_ptr
202 * class, which Cgu::SharedHandle does not (there is a
203 * Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle
204 * and is only usable with GObjects).
205 *
206 * If the library is compiled with the
207 * \--with-glib-memory-slices-no-compat configuration option, as
208 * mentioned Cgu::SharedHandle constructs its reference counting
209 * internals using glib memory slices. Although it is safe in a
210 * multi-threaded program if glib < 2.32 is installed to construct a
211 * static SharedHandle object in global namespace (that is, prior to
212 * g_thread_init() being called) by means of the default constructor
213 * and/or a pointer argument of NULL, it is not safe if constructed
214 * with a non-NULL pointer value. If glib >= 2.32 is installed,
215 * global objects with memory slices are safe in all
216 * circumstances. (Having said that, it would be highly unusual to
217 * have global SharedHandle objects.)
218 */
219
220 /********************* here are some deleter classes *******************/
221
222 /**
223 * @class StandardArrayDelete shared_handle.h c++-gtk-utils/shared_handle.h
224 * @brief A deleter functor for use as the second (Dealloc) template
225 * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
226 * template classes, which calls the C++ delete[] expression.
227 * @ingroup handles
228 * @details This functor enables those classes to manage arrays
229 * created with the new expression. It is the default type of the
230 * second template paramenter of those classes.
231 */
232 template <class T> class StandardArrayDelete {
233 public:
234 void operator()(T obj) {
235 delete[] obj;
236 }
237 };
238
239 /**
240 * @class CFree shared_handle.h c++-gtk-utils/shared_handle.h
241 * @brief A deleter functor for use as the second (Dealloc) template
242 * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
243 * template classes, which calls std::free.
244 * @ingroup handles
245 * @details This functor enables those classes to manage memory
246 * allocated with std::malloc(), std::calloc() and std::realloc(). It
247 * can also be used as the second template parameter of
248 * std::unique_ptr objects.
249 */
250 class CFree {
251 public:
252 void operator()(const void* obj) noexcept {
253 std::free(const_cast<void*>(obj));
254 }
255 };
256
257 /**
258 * @class GFree shared_handle.h c++-gtk-utils/shared_handle.h
259 * @brief A deleter functor for use as the second (Dealloc) template
260 * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
261 * template classes, which calls glib's g_free().
262 * @ingroup handles
263 * @details This functor enables those classes to manage memory
264 * allocated by glib or gtk functions which requires to be freed with
265 * g_free(). It is used in the typedefs @ref GcharSharedHandleAnchor
266 * "GcharSharedHandle" and @ref GcharScopedHandleAnchor
267 * "GcharScopedHandle". It can also be used as the second template
268 * parameter of std::unique_ptr objects.
269 */
270 class GFree {
271 public:
272 void operator()(const void* obj) noexcept {
273 g_free(const_cast<void*>(obj));
274 }
275 };
276
277 /**
278 * @class GSliceFree shared_handle.h c++-gtk-utils/shared_handle.h
279 * @brief A deleter functor for use as the second (Dealloc) template
280 * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
281 * template classes, which calls glib's g_slice_free1().
282 * @ingroup handles
283 *
284 * @details This functor enables those classes to manage a memory
285 * block allocated using glib memory slices. The managed memory block
286 * to be deleted by the GSliceFree functor must have the same size as
287 * the size of the object for which the functor is instantiated by
288 * pointer, as for example as allocated with the g_slice_new,
289 * g_slice_new0 or g_slice_dup macros (in other words, the GSliceFree
290 * template parameter must match the argument passed to those macros):
291 * see the example below. Use GSliceFreeSize where it is necessary or
292 * more convenient to have the size of the block to be freed as the
293 * template parameter. Use GSliceDestroy where the memory holds a C++
294 * object constructed in the memory by the global placement new
295 * expression.
296 *
297 * The type of the template argument for the functor is a pointer to
298 * the managed type: it is the same as the first template argument of
299 * the relevant SharedHandle, SharedLockHandle or ScopedHandle object.
300 * For example:
301 *
302 * @code
303 * using namespace Cgu;
304 * SharedHandle<MyStruct*, GSliceFree<MyStruct*> > h(g_slice_new(MyStruct));
305 * ...
306 * @endcode
307 *
308 * The availability of this functor is not dependent on the library
309 * having been installed with the \--with-glib-memory-slices-compat or
310 * \--with-glib-memory-slices-no-compat configuration option (see @ref
311 * Memory for further details of those options).
312 */
313 template <class T> class GSliceFree {
314 public:
315 void operator()(T obj) noexcept {
316 g_slice_free1(sizeof(*obj), (void*)obj);
317 }
318 };
319
320 /**
321 * @class GSliceDestroy shared_handle.h c++-gtk-utils/shared_handle.h
322 * @brief A deleter functor for use as the second (Dealloc) template
323 * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
324 * template classes, which calls glib's g_slice_free1(), but before
325 * doing so also explicitly calls the destructor of a C++ object
326 * constructed in the memory.
327 * @ingroup handles
328 *
329 * @details The managed memory block to be deleted by the
330 * GSliceDestroy functor must have the same size as the size of the
331 * object for which the functor is instantiated by pointer, as for
332 * example as allocated with the g_slice_new or g_slice_new0 macros
333 * (in other words, the GSliceDestroy template parameter must match
334 * the argument passed to those macros), and the memory block must
335 * have had that object constructed in it with the global placement
336 * new expression: see the example below. Sometimes it is more
337 * convenient to implement C++ objects in glib memory slices that way,
338 * rather than to have custom new and delete member operators of the
339 * classes concerned which use glib's g_slice_*(). However, a
340 * SharedHandle class with a GSliceDestroy deleter is not as easy to
341 * use as the SharedPtr class, as SharedHandle has no operator*() nor
342 * operator->() method (the get() method would have to be used to
343 * obtain the underlying pointer).
344 *
345 * One consequence of the static sizing (and so typing) of memory
346 * slices is that a GSliceDestroy object instantiated for the
347 * management of a particular class must not be used by a
348 * SharedHandle, SharedLockHandle or ScopedHandle object which
349 * attempts to manage a class derived from it. This comes back to the
350 * point that the GSliceDestroy template parameter must match the
351 * argument passed to the g_slice_new or g_slice_new0 macros.
352 *
353 * The type of the template argument for the functor is a pointer to
354 * the managed type: it is the same as the first template argument of
355 * the relevant SharedHandle, SharedLockHandle or ScopedHandle object.
356 * For example, to construct a SharedHandle managing an object of type
357 * MyClass to be constructed in a glib memory slice in an exception
358 * safe way:
359 *
360 * @code
361 * using namespace Cgu;
362 * SharedHandle<MyClass*, GSliceDestroy<MyClass*> > h; // won't throw
363 * { // scope block for p variable
364 * MyClass* p = g_slice_new(MyClass);
365 * try {new(p) MyClass;} // MyClass constructor might throw
366 * catch(...) {
367 * g_slice_free(MyClass, p);
368 * throw;
369 * }
370 * h.reset(p); // might throw but if so cleans up
371 * }
372 * ...
373 * @endcode
374 *
375 * The availability of this functor is not dependent on the library
376 * having been installed with the \--with-glib-memory-slices-compat or
377 * \--with-glib-memory-slices-no-compat configuration option (see @ref
378 * Memory for further details of those options).
379 */
380 template <class T> class GSliceDestroy {
381 template <class U> void destroy(U& obj) {obj.~U();}
382 public:
383 void operator()(T obj) {
384 destroy(*obj);
385 g_slice_free1(sizeof(*obj), (void*)obj);
386 }
387 };
388
389 /**
390 * @class GSliceFreeSize shared_handle.h c++-gtk-utils/shared_handle.h
391 * @brief A deleter functor for use as the second (Dealloc) template
392 * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
393 * template classes, which calls glib's g_slice_free1().
394 * @ingroup handles
395 *
396 * @details This functor enables those classes to manage memory
397 * allocated with g_slice_alloc(), g_slice_alloc0() or g_slice_copy().
398 * It is an alternative to using GSliceFree where, instead of the
399 * template parameter being a pointer to a particular managed type,
400 * the size of the memory block to be freed is passed, so enabling it
401 * to be more conveniently used to free memory containing arrays of
402 * built-in types or of PODSs. Use GSliceDestroy where the memory
403 * holds a C++ object constructed in the memory by the global
404 * placement new expression.
405 *
406 * The type of the template argument for the functor is an integer
407 * type (gsize) and is the size of the block to be managed. For
408 * example:
409 *
410 * @code
411 * using namespace Cgu;
412 * SharedHandle<char*, GSliceFreeSize<10> > h(static_cast<char*>(g_slice_alloc(10)));
413 * ...
414 * @endcode
415 *
416 * The availability of this functor is not dependent on the library
417 * having been installed with the \--with-glib-memory-slices-compat or
418 * \--with-glib-memory-slices-no-compat configuration option (see @ref
419 * Memory for further details of those options).
420 */
421 template <gsize block_size> class GSliceFreeSize {
422 public:
423 void operator()(const void* obj) noexcept {
424 g_slice_free1(block_size, const_cast<void*>(obj));
425 }
426 };
427
428 /*
429 * we could provide a functor class for
430 * g_slice_free_chain_with_offset() such as:
431 *
432 * template <class T, gsize offset> class GSliceFreeChain {
433 * public:
434 * void operator()(T obj) {
435 * g_slice_free_chain_with_offset(sizeof(*obj), (void*)obj, offset);
436 * }
437 * };
438 *
439 * However, this is not going to be particularly useful because the
440 * G_STRUCT_OFFSET macro and/or C's offsetof macro, needed to provide
441 * the value for the offset parameter, do not work for other than
442 * PODSs. g_slice_free_chain_with_offset() is intended for internal
443 * implementations and in the event of a user wanting such memory
444 * management it is best achieved by having custom new[] and delete[]
445 * member operators of the class concerned which use glib's
446 * g_slice_*() directly.
447 */
448
449 /********************* define some typedefs for Glib ******************/
450
451 template <class T, class Dealloc> class SharedHandle;
452 template <class T, class Dealloc> class ScopedHandle;
453
454 /**
455 * @typedef GcharSharedHandle.
456 * @brief A handle comprising a typed instance of the SharedHandle
457 * class for gchar* arrays and strings
458 * @anchor GcharSharedHandleAnchor
459 * @ingroup handles
460 * \#include <c++-gtk-utils/shared_handle.h>
461 */
462 typedef SharedHandle<gchar*, GFree> GcharSharedHandle;
463
464 /**
465 * @typedef GcharScopedHandle.
466 * @brief A handle comprising a typed instance of the ScopedHandle
467 * class for gchar* arrays and strings
468 * @anchor GcharScopedHandleAnchor
469 * @ingroup handles
470 * \#include <c++-gtk-utils/shared_handle.h>
471 */
472 typedef ScopedHandle<gchar*, GFree> GcharScopedHandle;
473
474
475 /******************* now the handle class definitions *****************/
476
477 /**
478 * @class SharedHandleError shared_handle.h c++-gtk-utils/shared_handle.h
479 * @brief This is an exception struct thrown as an alternative to
480 * deleting a managed object when internal memory allocation for
481 * SharedHandle or SharedLockHandle fails in their reset() method or
482 * in their constructor which takes a pointer.
483 * @sa SharedHandle SharedLockHandle SharedHandleAllocFail
484 * @ingroup handles
485 *
486 * This is an exception struct thrown as an alternative to deleting a
487 * managed object when SharedHandle<T>::SharedHandle(T),
488 * SharedLockHandle<T>::SharedLockHandle(T), SharedHandle<T>::reset(T)
489 * or SharedLockHandle<T>::reset(T) would otherwise throw
490 * std::bad_alloc. To make those methods do that,
491 * Cgu::SharedHandleAllocFail::leave is passed as their second
492 * argument.
493 *
494 * If the exception is thrown, the struct has a member 'obj' of type
495 * T, which is a pointer to the object or array originally passed to
496 * those methods, so the user can deal with it appropriately. This
497 * enables the result of the new expression to be passed directly as
498 * the argument to those methods without giving rise to a resource
499 * leak, as in:
500 *
501 * @code
502 * using namespace Cgu;
503 * SharedHandle<T*> s; // doesn't throw
504 * try {
505 * s.reset(new T[2], SharedHandleAllocFail::leave); // both T allocation and reset() might throw
506 * }
507 * catch (std::bad_alloc&) {
508 * ...
509 * }
510 * catch (SharedHandleError<T*>& e) {
511 * e.obj[0].do_something();
512 * e.obj[1].do_something();
513 * ...
514 * }
515 * ...
516 * @endcode
517 *
518 * As above, a catch block will need to deal with std::bad_alloc (if
519 * the call to the new expression when creating the T object fails)
520 * as well as SharedHandleError (if the call to the new expression in
521 * the reset() method fails after a valid T object has been
522 * constructed).
523 */
524
525 template <class T> struct SharedHandleError: public std::exception {
526 T obj;
527 virtual const char* what() const throw() {return "SharedHandleError\n";}
528 SharedHandleError(T p): obj(p) {}
529 };
530
531 /**
532 * enum Cgu::SharedHandleAllocFail::Leave
533 * The enumerator Cgu::SharedHandleAllocFail::leave is passed as the
534 * second argument of the reset() method of SharedHandle or
535 * SharedLockHandle in order to prevent the method deleting the object
536 * passed to it if reset() fails internally because of memory
537 * exhaustion.
538 * @ingroup handles
539 */
540 namespace SharedHandleAllocFail {
541 enum Leave {leave};
542 }
543
544 template <class T, class Dealloc = StandardArrayDelete<T>> class SharedHandle {
545
546 Dealloc deleter;
547
548 #ifndef DOXYGEN_PARSING
549 struct RefItems {
550 unsigned int* ref_count_p;
551 T obj;
552 } ref_items;
553 #endif
554
555 void unreference() {
556 if (!ref_items.ref_count_p) return;
557 --(*ref_items.ref_count_p);
558 if (*ref_items.ref_count_p == 0) {
559 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
560 g_slice_free(unsigned int, ref_items.ref_count_p);
561 #else
562 delete ref_items.ref_count_p;
563 #endif
564 deleter(ref_items.obj);
565 }
566 }
567
568 void reference() noexcept {
569 if (!ref_items.ref_count_p) return;
570 ++(*ref_items.ref_count_p);
571 }
572
573 public:
574 /**
575 * Constructor taking an unmanaged object.
576 * @param ptr The object which the SharedHandle is to manage (if
577 * any).
578 * @exception std::bad_alloc This constructor will not throw if the
579 * 'ptr' argument has a NULL value (the default), otherwise it might
580 * throw std::bad_alloc if memory is exhausted and the system throws
581 * in that case. If such an exception is thrown, this constructor is
582 * exception safe (it does not leak resources), but as well as
583 * cleaning itself up this constructor will also delete the managed
584 * object passed to it to avoid a memory leak. If such automatic
585 * deletion is not wanted in that case, use the version of this
586 * constructor taking a Cgu::SharedHandleAllocFail::Leave tag argument.
587 * @note std::bad_alloc will not be thrown if the library has been
588 * installed using the \--with-glib-memory-slices-no-compat
589 * configuration option: instead glib will terminate the program if it
590 * is unable to obtain memory from the operating system.
591 */
592 explicit SharedHandle(T ptr = 0) {
593
594 if ((ref_items.obj = ptr)) { // not NULL
595 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
596 ref_items.ref_count_p = g_slice_new(unsigned int);
597 *ref_items.ref_count_p = 1;
598 #else
599 try {
600 ref_items.ref_count_p = new unsigned int(1);
601 }
602 catch (...) {
603 deleter(ptr); // if allocating the int referenced by ref_items.ref_count_p
604 // has failed then delete the object to be referenced to
605 // avoid a memory leak
606 throw;
607 }
608 #endif
609 }
610 else ref_items.ref_count_p = 0;
611 }
612
613 /**
614 * Constructor taking an unmanaged object.
615 * @param ptr The object which the SharedHandle is to manage
616 * @param tag Passing the tag emumerator
617 * Cgu::SharedHandleAllocFail::leave causes this constructor not to
618 * delete the new managed object passed as the 'ptr' argument in the
619 * event of internal allocation in this method failing because of
620 * memory exhaustion (in that event, Cgu::SharedHandleError will be
621 * thrown).
622 * @exception Cgu::SharedHandleError This constructor might throw
623 * Cgu::SharedHandleError if memory is exhausted and the system would
624 * otherwise throw std::bad_alloc in that case. This constructor is
625 * exception safe (it does not leak resources), and if such an
626 * exception is thrown it will clean itself up, but it will not
627 * attempt to delete the new managed object passed to it. Access to
628 * the object passed to the 'ptr' argument can be obtained via the
629 * thrown Cgu::SharedHandleError object.
630 * @note 1. On systems with over-commit/lazy-commit combined with
631 * virtual memory (swap), it is rarely useful to check for memory
632 * exhaustion, so in those cases this version of the constructor will
633 * not be useful.
634 * @note 2. If the library has been installed using the
635 * \--with-glib-memory-slices-no-compat configuration option this
636 * version of the constructor will also not be useful: instead glib
637 * will terminate the program if it is unable to obtain memory from
638 * the operating system.
639 */
640 SharedHandle(T ptr, Cgu::SharedHandleAllocFail::Leave tag) {
641
642 if ((ref_items.obj = ptr)) { // not NULL
643 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
644 ref_items.ref_count_p = g_slice_new(unsigned int);
645 *ref_items.ref_count_p = 1;
646 #else
647 try {
648 ref_items.ref_count_p = new unsigned int(1);
649 }
650 catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
651 throw SharedHandleError<T>(ptr);
652 }
653 #endif
654 }
655 else ref_items.ref_count_p = 0;
656 }
657
658 /**
659 * Causes the SharedHandle to cease to manage its managed object (if
660 * any), deleting it if this is the last SharedHandle object managing
661 * it. If the argument passed is not NULL, the SharedHandle object
662 * will manage the new object passed (which must not be managed by any
663 * other SharedHandle object). This method is exception safe, but see
664 * the comments below on std::bad_alloc.
665 * @param ptr NULL (the default), or a new unmanaged object to manage.
666 * @exception std::bad_alloc This method will not throw if the 'ptr'
667 * argument has a NULL value (the default) and the destructor of a
668 * managed object does not throw, otherwise it might throw
669 * std::bad_alloc if memory is exhausted and the system throws in that
670 * case. Note that if such an exception is thrown then this method
671 * will do nothing (it is strongly exception safe and will continue to
672 * manage the object it was managing prior to the call), except that
673 * it will delete the new managed object passed to it to avoid a
674 * memory leak. If such automatic deletion in the event of such an
675 * exception is not wanted, use the reset() method taking a
676 * Cgu::SharedHandleAllocFail::Leave tag type as its second argument.
677 * @note std::bad_alloc will not be thrown if the library has been
678 * installed using the \--with-glib-memory-slices-no-compat
679 * configuration option: instead glib will terminate the program if it
680 * is unable to obtain memory from the operating system.
681 */
682 void reset(T ptr = 0) {
683 SharedHandle tmp(ptr);
684 std::swap(ref_items, tmp.ref_items);
685 }
686
687 /**
688 * Causes the SharedHandle to cease to manage its managed object (if
689 * any), deleting it if this is the last SharedHandle object managing
690 * it. The SharedHandle object will manage the new object passed
691 * (which must not be managed by any other SharedHandle object). This
692 * method is exception safe, but see the comments below on
693 * Cgu::SharedHandleError.
694 * @param ptr A new unmanaged object to manage (if no new object is to
695 * be managed, use the version of reset() taking a default value of
696 * NULL).
697 * @param tag Passing the tag emumerator
698 * Cgu::SharedHandleAllocFail::leave causes this method not to delete
699 * the new managed object passed as the 'ptr' argument in the event of
700 * internal allocation in this method failing because of memory
701 * exhaustion (in that event, Cgu::SharedHandleError will be thrown).
702 * @exception Cgu::SharedHandleError This method might throw
703 * Cgu::SharedHandleError if memory is exhausted and the system would
704 * otherwise throw std::bad_alloc in that case. Note that if such an
705 * exception is thrown then this method will do nothing (it is
706 * strongly exception safe and will continue to manage the object it
707 * was managing prior to the call), and it will not attempt to delete
708 * the new managed object passed to it. Access to the object passed
709 * to the 'ptr' argument can be obtained via the thrown
710 * Cgu::SharedHandleError object.
711 * @note 1. On systems with over-commit/lazy-commit combined with
712 * virtual memory (swap), it is rarely useful to check for memory
713 * exhaustion, so in those cases this version of the reset() method
714 * will not be useful.
715 * @note 2. If the library has been installed using the
716 * \--with-glib-memory-slices-no-compat configuration option this
717 * version of the reset() method will also not be useful: instead glib
718 * will terminate the program if it is unable to obtain memory from
719 * the operating system.
720 */
721 void reset(T ptr, Cgu::SharedHandleAllocFail::Leave tag) {
722 SharedHandle tmp(ptr, tag);
723 std::swap(ref_items, tmp.ref_items);
724 }
725
726 /**
727 * The copy constructor does not throw.
728 * @param sh_hand The handle to be copied.
729 */
730 SharedHandle(const SharedHandle& sh_hand) noexcept {
731 ref_items = sh_hand.ref_items;
732 reference();
733 }
734
735 /**
736 * The move constructor does not throw. It has move semantics.
737 * @param sh_hand The handle to be moved.
738 */
739 SharedHandle(SharedHandle&& sh_hand) noexcept {
740 ref_items = sh_hand.ref_items;
741 sh_hand.ref_items.ref_count_p = 0;
742 sh_hand.ref_items.obj = 0;
743 }
744
745 /**
746 * This method (and so copy or move assignment) does not throw unless
747 * the destructor of a managed object throws.
748 * @param sh_hand the assignor.
749 * @return The SharedHandle object after assignment.
750 */
751 // having a value type as the argument, rather than reference to const
752 // and then initialising a tmp object, gives the compiler more scope
753 // for optimisation, and also caters for r-values without a separate
754 // overload
755 SharedHandle& operator=(SharedHandle sh_hand) {
756 std::swap(ref_items, sh_hand.ref_items);
757 return *this;
758 }
759
760 /**
761 * This method does not throw.
762 * @return A pointer to the handled object (or NULL if none is
763 * handled).
764 */
765 T get() const noexcept {return ref_items.obj;}
766
767 /**
768 * This method does not throw.
769 * @return A pointer to the handled object (or NULL if none is
770 * handled).
771 */
772 operator T() const noexcept {return ref_items.obj;}
773
774 /**
775 * This method does not throw.
776 * @return The number of SharedHandle objects referencing the managed
777 * object (or 0 if none is managed by this SharedHandle).
778 */
779 unsigned int get_refcount() const noexcept {return (ref_items.ref_count_p) ? *ref_items.ref_count_p : 0;}
780
781 /**
782 * The destructor does not throw unless the destructor of a handled
783 * object throws - that should never happen.
784 */
785 ~SharedHandle() {unreference();}
786 };
787
788 /**
789 * @class ScopedHandle shared_handle.h c++-gtk-utils/shared_handle.h
790 * @brief This is a generic scoped class for managing the lifetime of objects
791 * allocated on freestore.
792 * @ingroup handles
793 * @sa SharedHandle SharedLockHandle SharedHandleError
794 * @sa StandardArrayDelete CFree GFree GerrorFree GSliceFree GSliceFreeSize GSliceDestroy
795 *
796 * This class deletes its object as soon as it goes out of scope. It
797 * can be viewed as a SharedHandle which cannot be copy assigned to or
798 * used as the argument to a copy constructor and therefore which
799 * cannot have a reference count of more than 1.
800 *
801 * ScopedHandle objects can be instantiated for pointers to constant
802 * objects (such as ScopedHandle<const char*>), provided the deleter
803 * functor will take such pointers.
804 *
805 * This library provides StandardArrayDelete, CFree, GFree,
806 * GerrorFree, GSliceFree, GSliceFreeSize and GSliceDestroy deleter
807 * functors, which can be used as the second template parameter of the
808 * ScopedHandle class. StandardArrayDelete is the default, and some
809 * typedef'ed instances of ScopedHandle for gchar (with the GFree
810 * deleter) and for GError (with the GerrorFree deleter) are provided:
811 * @ref GcharScopedHandleAnchor "GcharScopedHandle" and @ref
812 * GerrorScopedHandleAnchor "GerrorScopedHandle")
813 *
814 * @b Comparison @b with @b std::unique_ptr
815 *
816 * This class is mainly retained to retain compatibility with series
817 * 1.2 of the library, since most of the things that can be done with
818 * it can also be done using std::unique_ptr. However, this class is
819 * a little easier to use when managing objects with associated C
820 * functions (such as in glib), because it provides a type conversion
821 * operator.
822 *
823 * From version 2.2.2, this class has a move constructor and move
824 * assignment operator. Prior to that, it could not be moved from or
825 * to.
826 */
827
828 template <class T, class Dealloc = StandardArrayDelete<T>> class ScopedHandle {
829 Dealloc deleter;
830 T obj;
831 public:
832 /**
833 * This class cannot be copied. The copy constructor is deleted.
834 */
835 ScopedHandle(const ScopedHandle&) = delete;
836
837 /**
838 * This class cannot be copied. The copy assignment operator is
839 * deleted.
840 */
841 ScopedHandle& operator=(const ScopedHandle&) = delete;
842
843 /**
844 * The move constructor does not throw.
845 * @param sc_hand The handle to be moved.
846 *
847 * Since 2.0.19/2.2.2
848 */
849 ScopedHandle(ScopedHandle&& sc_hand) noexcept {
850 obj = sc_hand.obj;
851 sc_hand.obj = 0;
852 }
853
854 /**
855 * The move assignment operator. It will delete the object managed
856 * prior to the move, if any. It does not throw unless the destructor
857 * of that object throws.
858 * @param sc_hand The handle to be moved.
859 * @return The ScopedHandle object after move assignment.
860 *
861 * Since 2.0.19/2.2.2
862 */
863 ScopedHandle& operator=(ScopedHandle&& sc_hand) {
864 reset(sc_hand.release());
865 return *this;
866 }
867
868 /**
869 * This constructor does not throw.
870 * @param ptr The object which the ScopedHandle is to manage (if
871 * any).
872 *
873 * ScopedHandle objects can be instantiated for pointers to constant
874 * objects (such as SharedHandle<const char*>), provided the deleter
875 * functor will take such pointers.
876 */
877 explicit ScopedHandle(T ptr = 0) noexcept: obj(ptr) {}
878
879 /**
880 * Causes the ScopedHandle to delete its managed object (if any), and
881 * if the argument passed is not NULL, the ScopedHandle object will
882 * manage the new object passed (which must not be managed by any
883 * other ScopedHandle object). This method does not throw (assuming
884 * the destructor of a managed object does not throw).
885 * @param ptr NULL (the default), or a new unmanaged object to manage.
886 */
887 void reset(T ptr = 0) {
888 std::swap(obj, ptr);
889 if (ptr) deleter(ptr); // ptr now points to the original managed object
890 }
891
892 /**
893 * Causes the ScopedHandle to cease to manage the handled object, but
894 * does not delete that object. This method does not throw.
895 * @return A pointer to the previously handled object (or NULL if none
896 * was handled).
897 */
898 T release() noexcept {T tmp = obj; obj = 0; return tmp;}
899
900 /**
901 * This method does not throw.
902 * @return A pointer to the handled object (or NULL if none is
903 * handled).
904 */
905 T get() const noexcept {return obj;}
906
907 /**
908 * This method does not throw.
909 * @return A pointer to the handled object (or NULL if none is
910 * handled).
911 */
912 operator T() const noexcept {return obj;}
913
914 /**
915 * The destructor does not throw unless the destructor of a handled
916 * object throws - that should never happen.
917 */
918 ~ScopedHandle() {if (obj) deleter(obj);}
919 };
920
921
922 /**
923 * @class SharedLockHandle shared_handle.h c++-gtk-utils/shared_handle.h
924 * @brief This is a generic class for managing the lifetime of objects
925 * allocated on freestore, with a thread safe reference count..
926 * @ingroup handles
927 * @sa SharedHandle ScopedHandle SharedHandleError
928 * @sa StandardArrayDelete CFree GFree GerrorFree GSliceFree GSliceFreeSize GSliceDestroy
929 *
930 * Class SharedLockHandle is a version of the SharedHandle class which
931 * includes synchronization so that it can handle objects accessed in
932 * multiple threads (although the word Lock is in the title, by
933 * default it uses glib atomic functions to access the reference count
934 * rather than a mutex, so the overhead should be very small). Note
935 * that only the reference count is protected, so this is thread safe
936 * in the sense in which a raw pointer is thread safe. A shared
937 * handle accessed in one thread referencing a particular object is
938 * thread safe as against another shared handle accessing the same
939 * object in a different thread. It is thus suitable for use in
940 * different standard C++ containers which exist in different threads
941 * but which contain shared objects by reference. But:
942 *
943 * 1. If the referenced object is to be modified in one thread and
944 * read or modified in another thread an appropriate mutex for the
945 * referenced object is required (unless that referenced object
946 * does its own locking).
947 * 2. If the same instance of shared handle is to be modified in one
948 * thread (by assigning to the handle so that it references a
949 * different object, or by moving from it), and copied (assigned
950 * from or used as the argument of a copy constructor), accessed,
951 * destroyed or modified in another thread, a mutex for that
952 * instance of shared handle is required.
953 * 3. Objects referenced by shared handles which are objects for
954 * which POSIX provides no guarantees (in the main, those which
955 * are not built-in types), such as strings and similar
956 * containers, may not support concurrent reads in different
957 * threads. That depends on the library implementation concerned
958 * (but a fully conforming C++11 library implementation is
959 * required to permit concurrent calls to the const methods of any
960 * object from the standard library without external
961 * synchronization, so long as no non-const method is called
962 * concurrently). For cases where concurrent reads are not
963 * supported, a mutex for the referenced object will be required
964 * when reading any given instance of such an object in more than
965 * one thread by dereferencing any shared handles referencing it
966 * (and indeed, when not using shared handles at all).
967 *
968 * SharedLockHandle objects can be instantiated for pointers to
969 * constant objects (such as SharedLockHandle<const char*>), provided
970 * the deleter functor will take such pointers.
971 *
972 * This library provides StandardArrayDelete, CFree, GFree,
973 * GerrorFree, GSliceFree, GSliceFreeSize and GSliceDestroy deleter
974 * functors, which can be used as the second template parameter of the
975 * SharedLockHandle class. StandardArrayDelete is the default.
976 *
977 * As mentioned, by default glib atomic functions are used to provide
978 * thread-safe manipulation of the reference count. However, the
979 * symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX can be defined so that the
980 * library uses mutexes instead, which might be useful for some
981 * debugging purposes. Note that if CGU_SHARED_LOCK_HANDLE_USE_MUTEX
982 * is to be defined, this is best done by textually amending the
983 * shared_handle.h header file before the library is compiled. This
984 * will ensure that everything in the program and the library which
985 * includes the shared_handle.h header is guaranteed to see the same
986 * definitions so that the C++ standard's one-definition-rule is
987 * complied with.
988 *
989 * @b Comparison @b with @b std::shared_ptr
990 *
991 * Although the semantics of std::shared_ptr in C++11/14 are not
992 * particularly suited to managing either arrays or C objects with
993 * accessor functions (such as in glib), most of the things that can
994 * be done by this class can be done by using std::shared_ptr with a
995 * specialised deleter. However, this class is retained in the
996 * c++-gtk-utils library not only to retain compatibility with series
997 * 1.2 of the library, but also to cater for some cases not met (or
998 * not so easily met) by std::shared_ptr:
999 *
1000 * 1. The Cgu::SharedLockHandle class takes its deleter as a template
1001 * parameter, which means that typedefs can be used to enable
1002 * handles for particular deleters to be easily created (and as
1003 * mentioned, this library provides a number of pre-formed deleter
1004 * functors and typedefs for them). With std::shared_ptr, custom
1005 * deleters must be passed to the shared_ptr constructor on every
1006 * occasion a shared_ptr is constructed to manage a new object (and
1007 * they cannot be templated as a typedef).
1008 * 2. Glib memory slices provide an efficient small object allocator
1009 * (they are likely to be significantly more efficient than global
1010 * operator new()/new[](), which generally hand off to malloc(),
1011 * and whilst malloc() is good for large block allocations it is
1012 * generally poor as a small object allocator). Internal
1013 * Cgu::SharedLockHandle allocation using glib memory slices can be
1014 * achieved by compiling the library with the
1015 * \--with-glib-memory-slices-no-compat configuration option.
1016 * 3. If glib memory slices are not used (which do not throw),
1017 * constructing a shared pointer for a new managed object (or
1018 * calling reset() for a new managed object) might throw if
1019 * internal allocation fails. Although by default the
1020 * Cgu::SharedLockHandle implementation will delete the new managed
1021 * object in such a case, it also provides an alternative
1022 * constructor and reset() method which instead enable the new
1023 * object to be accessed via the thrown exception object so that
1024 * user code can decide what to do; std::shared_ptr deletes the new
1025 * object in every case.
1026 * 4. A user can explicitly state whether the shared handle object is
1027 * to have atomic increment and decrement-and-test with respect to
1028 * the reference count so that the reference count is thread safe
1029 * ('no' in the case of Cgu::SharedHandle, and 'yes' in the case of
1030 * Cgu::SharedLockHandle). Using atomic functions is unnecessary
1031 * if the managed object concerned is only addressed in one thread
1032 * (and might cause unwanted cache flushing in certain
1033 * circumstances). std::shared_ptr will generally always use
1034 * atomic functions with respect to its reference count in a
1035 * multi-threaded program.
1036 *
1037 * In favour of std::shared_ptr, it has an associated std::weak_ptr
1038 * class, which Cgu::SharedLockHandle does not (there is a
1039 * Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle
1040 * and is only usable with GObjects). In addition shared_ptr objects
1041 * have some atomic store, load and exchange functions provided for
1042 * them which enable concurrent modifications of the same instance of
1043 * shared_ptr in different threads to have defined results.
1044 *
1045 * If the library is compiled with the
1046 * \--with-glib-memory-slices-no-compat configuration option, as
1047 * mentioned Cgu::SharedLockHandle constructs its reference counting
1048 * internals using glib memory slices. Although it is safe in a
1049 * multi-threaded program if glib < 2.32 is installed to construct a
1050 * static SharedLockHandle object in global namespace (that is, prior
1051 * to g_thread_init() being called) by means of the default
1052 * constructor and/or a pointer argument of NULL, it is not safe if
1053 * constructed with a non-NULL pointer value. If glib >= 2.32 is
1054 * installed, global objects with memory slices are safe in all
1055 * circumstances. (Having said that, it would be highly unusual to
1056 * have global SharedLockHandle objects.)
1057 */
1058
1059 template <class T, class Dealloc = StandardArrayDelete<T>> class SharedLockHandle {
1060
1061 Dealloc deleter;
1062
1063 #ifndef DOXYGEN_PARSING
1064 struct RefItems {
1065 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1066 Thread::Mutex* mutex_p;
1067 unsigned int* ref_count_p;
1068 #else
1069 gint* ref_count_p;
1070 #endif
1071 T obj;
1072 } ref_items;
1073 #endif
1074
1075 // SharedLockHandle<T, Dealloc>::unreference() does not throw exceptions
1076 // because Thread::Mutex::~Mutex(), Thread::Mutex::lock() and Thread::Mutex::unlock()
1077 // do not throw
1078 void unreference() {
1079 // we can (and should) check whether ref_items.ref_count_p is NULL without
1080 // a lock, because that member is specific to this SharedLockHandle object.
1081 // Only the integer pointed to by it is shared amongst SharedLockHandle
1082 // objects and requires locking
1083 if (!ref_items.ref_count_p) return;
1084 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1085 ref_items.mutex_p->lock();
1086 --(*ref_items.ref_count_p);
1087 if (*ref_items.ref_count_p == 0) {
1088 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1089 g_slice_free(unsigned int, ref_items.ref_count_p);
1090 # else
1091 delete ref_items.ref_count_p;
1092 # endif
1093 ref_items.mutex_p->unlock();
1094 delete ref_items.mutex_p;
1095 deleter(ref_items.obj);
1096 }
1097 else ref_items.mutex_p->unlock();
1098 #else
1099 if (g_atomic_int_dec_and_test(ref_items.ref_count_p)) {
1100 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1101 g_slice_free(gint, ref_items.ref_count_p);
1102 # else
1103 delete ref_items.ref_count_p;
1104 # endif
1105 deleter(ref_items.obj);
1106 }
1107 #endif
1108 }
1109
1110 // SharedLockHandle<T, Dealloc>::reference() does not throw exceptions because
1111 // Thread::Mutex::Lock::Lock() and Thread::Mutex::Lock::~Lock() do not throw
1112 void reference() noexcept {
1113 // we can (and should) check whether ref_items.ref_count_p is NULL without
1114 // a lock, because that member is specific to this SharedLockHandle object.
1115 // Only the integer pointed to by it is shared amongst SharedLockHandle
1116 // objects and requires locking
1117 if (!ref_items.ref_count_p) return;
1118 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1119 Thread::Mutex::Lock lock(*ref_items.mutex_p);
1120 ++(*ref_items.ref_count_p);
1121 #else
1122 g_atomic_int_inc(ref_items.ref_count_p);
1123 #endif
1124 }
1125
1126 public:
1127 /**
1128 * Constructor taking an unmanaged object.
1129 * @param ptr The object which the SharedLockHandle is to manage (if
1130 * any).
1131 * @exception std::bad_alloc This constructor will not throw if the
1132 * 'ptr' argument has a NULL value (the default), otherwise it might
1133 * throw std::bad_alloc if memory is exhausted and the system throws
1134 * in that case. If such an exception is thrown, this constructor is
1135 * exception safe (it does not leak resources), but as well as
1136 * cleaning itself up this constructor will also delete the managed
1137 * object passed to it to avoid a memory leak. If such automatic
1138 * deletion is not wanted in that case, use the version of this
1139 * constructor taking a Cgu::SharedHandleAllocFail::Leave tag
1140 * argument.
1141 * @note 1. std::bad_alloc will not be thrown if the library has been
1142 * installed using the \--with-glib-memory-slices-no-compat
1143 * configuration option: instead glib will terminate the program if it
1144 * is unable to obtain memory from the operating system.
1145 * @note 2. By default, glib atomic functions are used to provide
1146 * thread-safe manipulation of the reference count. However, the
1147 * header file shared_handle.h can be textually amended before the
1148 * library is compiled to define the symbol
1149 * CGU_SHARED_LOCK_HANDLE_USE_MUTEX so as to use mutexes instead,
1150 * which might be useful for some debugging purposes. Were that to be
1151 * done, Cgu::Thread::MutexError might be thrown by this constructor
1152 * if initialization of the mutex fails.
1153 */
1154 explicit SharedLockHandle(T ptr = 0) {
1155
1156 if ((ref_items.obj = ptr)) { // not NULL
1157 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1158 try {
1159 ref_items.mutex_p = new Thread::Mutex;
1160 }
1161 catch (...) {
1162 deleter(ptr); // if allocating the object referenced by ref_items.mutex_p
1163 // has failed then delete the object to be referenced to
1164 // avoid a memory leak
1165 throw;
1166 }
1167 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1168 ref_items.ref_count_p = g_slice_new(unsigned int);
1169 *ref_items.ref_count_p = 1;
1170 # else
1171 try {
1172 ref_items.ref_count_p = new unsigned int(1);
1173 }
1174 catch (...) {
1175 delete ref_items.mutex_p;
1176 deleter(ptr);
1177 throw;
1178 }
1179 # endif
1180 #else
1181 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1182 ref_items.ref_count_p = g_slice_new(gint);
1183 *ref_items.ref_count_p = 1;
1184 # else
1185 try {
1186 ref_items.ref_count_p = new gint(1);
1187 }
1188 catch (...) {
1189 deleter(ptr); // if allocating the int referenced by ref_items.ref_count_p
1190 // has failed then delete the object to be referenced to
1191 // avoid a memory leak
1192 throw;
1193 }
1194 # endif
1195 #endif
1196 }
1197 else {
1198 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1199 ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
1200 #endif
1201 ref_items.ref_count_p = 0;
1202 }
1203 }
1204
1205 /**
1206 * Constructor taking an unmanaged object.
1207 * @param ptr The object which the SharedLockHandle is to manage.
1208 * @param tag Passing the tag emumerator
1209 * Cgu::SharedHandleAllocFail::leave causes this constructor not to
1210 * delete the new managed object passed as the 'ptr' argument in the
1211 * event of internal allocation in this method failing because of
1212 * memory exhaustion (in that event, Cgu::SharedHandleError will be
1213 * thrown).
1214 * @exception Cgu::SharedHandleError This constructor might throw
1215 * Cgu::SharedHandleError if memory is exhausted and the system would
1216 * otherwise throw std::bad_alloc in that case. This constructor is
1217 * exception safe (it does not leak resources), and if such an
1218 * exception is thrown it will clean itself up, but it will not
1219 * attempt to delete the new managed object passed to it. Access to
1220 * the object passed to the 'ptr' argument can be obtained via the
1221 * thrown Cgu::SharedHandleError object.
1222 * @note 1. On systems with over-commit/lazy-commit combined with
1223 * virtual memory (swap), it is rarely useful to check for memory
1224 * exhaustion, so in those cases this version of the constructor will
1225 * not be useful.
1226 * @note 2. If the library has been installed using the
1227 * \--with-glib-memory-slices-no-compat configuration option this
1228 * version of the constructor will also not be useful: instead glib
1229 * will terminate the program if it is unable to obtain memory from
1230 * the operating system.
1231 * @note 3. By default, glib atomic functions are used to provide
1232 * thread-safe manipulation of the reference count. However, the
1233 * header file shared_handle.h can be textually amended before the
1234 * library is compiled to define the symbol
1235 * CGU_SHARED_LOCK_HANDLE_USE_MUTEX so as to use mutexes instead,
1236 * which might be useful for some debugging purposes. Were that to be
1237 * done, Cgu::SharedHandleError might be thrown by this constructor if
1238 * initialization of the mutex fails (even if the
1239 * \--with-glib-memory-slices-no-compat configuration option is
1240 * chosen).
1241 */
1242 SharedLockHandle(T ptr, Cgu::SharedHandleAllocFail::Leave tag) {
1243
1244 if ((ref_items.obj = ptr)) { // not NULL
1245 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1246 try {
1247 ref_items.mutex_p = new Thread::Mutex;
1248 }
1249 catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
1250 throw SharedHandleError<T>(ptr);
1251 }
1252 catch (Thread::MutexError&) { // as we are not rethrowing, make NPTL friendly
1253 throw SharedHandleError<T>(ptr);
1254 }
1255 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1256 ref_items.ref_count_p = g_slice_new(unsigned int);
1257 *ref_items.ref_count_p = 1;
1258 # else
1259 try {
1260 ref_items.ref_count_p = new unsigned int(1);
1261 }
1262 catch (std::bad_alloc&) {
1263 delete ref_items.mutex_p;
1264 throw SharedHandleError<T>(ptr);
1265 }
1266 # endif
1267 #else
1268 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1269 ref_items.ref_count_p = g_slice_new(gint);
1270 *ref_items.ref_count_p = 1;
1271 # else
1272 try {
1273 ref_items.ref_count_p = new gint(1);
1274 }
1275 catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
1276 throw SharedHandleError<T>(ptr);
1277 }
1278 # endif
1279 #endif
1280 }
1281 else {
1282 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1283 ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
1284 #endif
1285 ref_items.ref_count_p = 0;
1286 }
1287 }
1288
1289 /**
1290 * Causes the SharedLockHandle to cease to manage its managed object
1291 * (if any), deleting it if this is the last ShareLockHandle object
1292 * managing it. If the argument passed is not NULL, the
1293 * SharedLockHandle object will manage the new object passed (which
1294 * must not be managed by any other SharedLockHandle object).
1295 * @param ptr NULL (the default), or a new unmanaged object to manage.
1296 * @exception std::bad_alloc This method will not throw if the 'ptr'
1297 * argument has a NULL value (the default) and the destructor of a
1298 * managed object does not throw, otherwise it might throw
1299 * std::bad_alloc if memory is exhausted and the system throws in that
1300 * case. Note that if such an exception is thrown then this method
1301 * will do nothing (it is strongly exception safe and will continue to
1302 * manage the object it was managing prior to the call), except that
1303 * it will delete the new managed object passed to it to avoid a
1304 * memory leak. If such automatic deletion in the event of such an
1305 * exception is not wanted, use the reset() method taking a
1306 * Cgu::SharedHandleAllocFail::Leave tag type as its second argument.
1307 * @note 1. std::bad_alloc will not be thrown if the library has been
1308 * installed using the \--with-glib-memory-slices-no-compat
1309 * configuration option: instead glib will terminate the program if it
1310 * is unable to obtain memory from the operating system.
1311 * @note 2. By default, glib atomic functions are used to provide
1312 * thread-safe manipulation of the reference count. However, the
1313 * header file shared_handle.h can be textually amended before the
1314 * library is compiled to define the symbol
1315 * CGU_SHARED_LOCK_HANDLE_USE_MUTEX so as to use mutexes instead,
1316 * which might be useful for some debugging purposes. Were that to be
1317 * done, Cgu::Thread::MutexError might be thrown by this method if
1318 * initialization of the mutex fails.
1319 * @note 3. A SharedLockHandle object protects its reference count but
1320 * not the managed object or its other internals. The reset() method
1321 * should not be called by one thread in respect of a particular
1322 * SharedLockHandle object while another thread may be operating on,
1323 * copying or dereferencing the same instance of SharedLockHandle. It
1324 * is thread-safe as against another instance of SharedLockHandle
1325 * managing the same object.
1326 */
1327 void reset(T ptr = 0) {
1328 SharedLockHandle tmp(ptr);
1329 std::swap(ref_items, tmp.ref_items);
1330 }
1331
1332 /**
1333 * Causes the SharedLockHandle to cease to manage its managed object
1334 * (if any), deleting it if this is the last ShareLockHandle object
1335 * managing it. The SharedLockHandle object will manage the new
1336 * object passed (which must not be managed by any other
1337 * SharedLockHandle object). This method is exception safe, but see
1338 * the comments below on Cgu::SharedHandleError.
1339 * @param ptr A new unmanaged object to manage (if no new object is to
1340 * be managed, use the version of reset() taking a default value of
1341 * NULL).
1342 * @param tag Passing the tag emumerator
1343 * Cgu::SharedHandleAllocFail::leave causes this method not to delete
1344 * the new managed object passed as the 'ptr' argument in the event of
1345 * internal allocation in this method failing because of memory
1346 * exhaustion (in that event, Cgu::SharedHandleError will be thrown).
1347 * @exception Cgu::SharedHandleError This method might throw
1348 * Cgu::SharedHandleError if memory is exhausted and the system would
1349 * otherwise throw std::bad_alloc in that case. Note that if such an
1350 * exception is thrown then this method will do nothing (it is
1351 * strongly exception safe and will continue to manage the object it
1352 * was managing prior to the call), and it will not attempt to delete
1353 * the new managed object passed to it (if any). Access to the object
1354 * passed to the 'ptr' argument can be obtained via the thrown
1355 * Cgu::SharedHandleError object.
1356 * @note 1. A SharedLockHandle object protects its reference count but
1357 * not the managed object or its other internals. The reset() method
1358 * should not be called by one thread in respect of a particular
1359 * SharedLockHandle object while another thread may be operating on,
1360 * copying or dereferencing the same instance of SharedLockHandle. It
1361 * is thread-safe as against another instance of SharedLockHandle
1362 * managing the same object.
1363 * @note 2. On systems with over-commit/lazy-commit combined with
1364 * virtual memory (swap), it is rarely useful to check for memory
1365 * exhaustion, so in those cases this version of the reset() method
1366 * will not be useful.
1367 * @note 3. If the library has been installed using the
1368 * \--with-glib-memory-slices-no-compat configuration option this
1369 * version of the reset() method will also not be useful: instead glib
1370 * will terminate the program if it is unable to obtain memory from
1371 * the operating system.
1372 * @note 4. By default, glib atomic functions are used to provide
1373 * thread-safe manipulation of the reference count. However, the
1374 * header file shared_handle.h can be textually amended before the
1375 * library is compiled to define the symbol
1376 * CGU_SHARED_LOCK_HANDLE_USE_MUTEX so as to use mutexes instead,
1377 * which might be useful for some debugging purposes. Were that to be
1378 * done, Cgu::SharedHandleError might be thrown by this method if
1379 * initialization of the mutex fails (even if the
1380 * \--with-glib-memory-slices-no-compat configuration option is
1381 * chosen).
1382 */
1383 void reset(T ptr, Cgu::SharedHandleAllocFail::Leave tag) {
1384 SharedLockHandle tmp(ptr, tag);
1385 std::swap(ref_items, tmp.ref_items);
1386 }
1387
1388 /**
1389 * The copy constructor does not throw.
1390 * @param sh_hand The handle to be copied.
1391 */
1392 SharedLockHandle(const SharedLockHandle& sh_hand) noexcept {
1393 ref_items = sh_hand.ref_items;
1394 reference();
1395 }
1396
1397 /**
1398 * The move constructor does not throw. It has move semantics.
1399 * @param sh_hand The handle to be moved.
1400 */
1401 SharedLockHandle(SharedLockHandle&& sh_hand) noexcept {
1402 ref_items = sh_hand.ref_items;
1403 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1404 sh_hand.ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
1405 #endif
1406 sh_hand.ref_items.ref_count_p = 0;
1407 sh_hand.ref_items.obj = 0;
1408 }
1409
1410 /**
1411 * This method (and so copy or move assignment) does not throw unless
1412 * the destructor of a managed object throws.
1413 * @param sh_hand the assignor.
1414 * @return The SharedLockHandle object after assignment.
1415 */
1416 // having a value type as the argument, rather than reference to const
1417 // and then initialising a tmp object, gives the compiler more scope
1418 // for optimisation
1419 SharedLockHandle& operator=(SharedLockHandle sh_hand) {
1420 std::swap(ref_items, sh_hand.ref_items);
1421 return *this;
1422 }
1423
1424 /**
1425 * This method does not throw.
1426 * @return A pointer to the handled object (or NULL if none is
1427 * handled).
1428 */
1429 T get() const noexcept {return ref_items.obj;}
1430
1431 /**
1432 * This method does not throw.
1433 * @return A pointer to the handled object (or NULL if none is
1434 * handled).
1435 */
1436 operator T() const noexcept {return ref_items.obj;}
1437
1438 /**
1439 * This method does not throw.
1440 * @return The number of SharedLockHandle objects referencing the
1441 * managed object (or 0 if none is managed by this SharedLockHandle).
1442 * @note The return value may not be valid if another thread has
1443 * changed the reference count before the value returned by this
1444 * method is acted on. It is provided as a utility, but may not be
1445 * meaningful, depending on the intended usage.
1446 */
1447 unsigned int get_refcount() const noexcept {
1448 if (!ref_items.ref_count_p) return 0;
1449 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1450 Thread::Mutex::Lock lock(*ref_items.mutex_p);
1451 return *ref_items.ref_count_p;
1452 #else
1453 return g_atomic_int_get(ref_items.ref_count_p);
1454 #endif
1455 }
1456
1457 /**
1458 * The destructor does not throw unless the destructor of a handled
1459 * object throws - that should never happen.
1460 */
1461 ~SharedLockHandle() {unreference();}
1462 };
1463
1464 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
1465
1466 // we can use built-in operator == when comparing pointers referencing
1467 // different objects of the same type
1468 /**
1469 * @ingroup handles
1470 *
1471 * This comparison operator does not throw. It compares the addresses
1472 * of the managed objects.
1473 *
1474 * Since 2.0.0-rc2
1475 */
1476 template <class T, class Dealloc>
1477 bool operator==(const SharedHandle<T, Dealloc>& s1, const SharedHandle<T, Dealloc>& s2) noexcept {
1478 return (s1.get() == s2.get());
1479 }
1480
1481 /**
1482 * @ingroup handles
1483 *
1484 * This comparison operator does not throw. It compares the addresses
1485 * of the managed objects.
1486 *
1487 * Since 2.0.0-rc2
1488 */
1489 template <class T, class Dealloc>
1490 bool operator!=(const SharedHandle<T, Dealloc>& s1, const SharedHandle<T, Dealloc>& s2) noexcept {
1491 return !(s1 == s2);
1492 }
1493
1494 // we must use std::less rather than the < built-in operator for
1495 // pointers to objects not within the same array or object: "For
1496 // templates greater, less, greater_equal, and less_equal, the
1497 // specializations for any pointer type yield a total order, even if
1498 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
1499 /**
1500 * @ingroup handles
1501 *
1502 * This comparison operator does not throw unless std::less applied to
1503 * pointer types throws (which it would not do with any sane
1504 * implementation). It compares the addresses of the managed objects.
1505 *
1506 * Since 2.0.0-rc2
1507 */
1508 template <class T, class Dealloc>
1509 bool operator<(const SharedHandle<T, Dealloc>& s1, const SharedHandle<T, Dealloc>& s2) {
1510 return std::less<T>()(s1.get(), s2.get());
1511 }
1512
1513 /**
1514 * @ingroup handles
1515 *
1516 * This comparison operator does not throw. It compares the addresses
1517 * of the managed objects.
1518 *
1519 * Since 2.0.0-rc2
1520 */
1521 template <class T, class Dealloc>
1522 bool operator==(const SharedLockHandle<T, Dealloc>& s1, const SharedLockHandle<T, Dealloc>& s2) noexcept {
1523 return (s1.get() == s2.get());
1524 }
1525
1526 /**
1527 * @ingroup handles
1528 *
1529 * This comparison operator does not throw. It compares the addresses
1530 * of the managed objects.
1531 *
1532 * Since 2.0.0-rc2
1533 */
1534 template <class T, class Dealloc>
1535 bool operator!=(const SharedLockHandle<T, Dealloc>& s1, const SharedLockHandle<T, Dealloc>& s2) noexcept {
1536 return !(s1 == s2);
1537 }
1538
1539 /**
1540 * @ingroup handles
1541 *
1542 * This comparison operator does not throw unless std::less applied to
1543 * pointer types throws (which it would not do with any sane
1544 * implementation). It compares the addresses of the managed objects.
1545 *
1546 * Since 2.0.0-rc2
1547 */
1548 template <class T, class Dealloc>
1549 bool operator<(const SharedLockHandle<T, Dealloc>& s1, const SharedLockHandle<T, Dealloc>& s2) {
1550 return std::less<T>()(s1.get(), s2.get());
1551 }
1552
1553 #endif // CGU_USE_SMART_PTR_COMPARISON
1554
1555 } // namespace Cgu
1556
1557 // doxygen produces long filenames that tar can't handle:
1558 // we have generic documentation for std::hash specialisations
1559 // in doxygen.main.in
1560 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING)
1561 /* These structs allow SharedHandle and SharedLockHandle objects to be
1562 keys in unordered associative containers */
1563 namespace std {
1564 template <class T, class Dealloc>
1565 struct hash<Cgu::SharedHandle<T, Dealloc>> {
1566 typedef std::size_t result_type;
1567 typedef Cgu::SharedHandle<T, Dealloc> argument_type;
1568 result_type operator()(const argument_type& s) const {
1569 // this is fine: std::hash structs do not normally contain data and
1570 // std::hash<T*> certainly won't, so we don't have overhead constructing
1571 // std::hash<T*> on the fly
1572 return std::hash<T>()(s.get());
1573 }
1574 };
1575 template <class T, class Dealloc>
1576 struct hash<Cgu::SharedLockHandle<T, Dealloc>> {
1577 typedef std::size_t result_type;
1578 typedef Cgu::SharedLockHandle<T, Dealloc> argument_type;
1579 result_type operator()(const argument_type& s) const {
1580 // this is fine: std::hash structs do not normally contain data and
1581 // std::hash<T*> certainly won't, so we don't have overhead constructing
1582 // std::hash<T*> on the fly
1583 return std::hash<T>()(s.get());
1584 }
1585 };
1586 } // namespace std
1587 #endif // CGU_USE_SMART_PTR_COMPARISON
1588
1589 #endif
Cgu::GcharSharedHandle
SharedHandle< gchar *, GFree > GcharSharedHandle
A handle comprising a typed instance of the SharedHandle class for gchar* arrays and strings.
Definition: shared_handle.h:462
Cgu::SharedLockHandle::get
T get() const noexcept
Definition: shared_handle.h:1429
Cgu::SharedLockHandle::reset
void reset(T ptr, Cgu::SharedHandleAllocFail::Leave tag)
Definition: shared_handle.h:1383
Cgu
Definition: application.h:44
Cgu::SharedHandle::SharedHandle
SharedHandle(T ptr, Cgu::SharedHandleAllocFail::Leave tag)
Definition: shared_handle.h:640
Cgu::Thread::Mutex::lock
int lock() noexcept
Definition: mutex.h:147
Cgu::SharedHandleError
This is an exception struct thrown as an alternative to deleting a managed object when internal memor...
Definition: shared_handle.h:525
Cgu::CFree
A deleter functor for use as the second (Dealloc) template parameter of the SharedHandle,...
Definition: shared_handle.h:250
Cgu::ScopedHandle::get
T get() const noexcept
Definition: shared_handle.h:905
Cgu::StandardArrayDelete::operator()
void operator()(T obj)
Definition: shared_handle.h:234
Cgu::GFree
A deleter functor for use as the second (Dealloc) template parameter of the SharedHandle,...
Definition: shared_handle.h:270
Cgu::GSliceDestroy
A deleter functor for use as the second (Dealloc) template parameter of the SharedHandle,...
Definition: shared_handle.h:380
Cgu::GcharScopedHandle
ScopedHandle< gchar *, GFree > GcharScopedHandle
A handle comprising a typed instance of the ScopedHandle class for gchar* arrays and strings.
Definition: shared_handle.h:472
Cgu::SharedHandle::reset
void reset(T ptr=0)
Definition: shared_handle.h:682
Cgu::ScopedHandle::~ScopedHandle
~ScopedHandle()
Definition: shared_handle.h:918
Cgu::SharedHandle::get_refcount
unsigned int get_refcount() const noexcept
Definition: shared_handle.h:779
Cgu::ScopedHandle::release
T release() noexcept
Definition: shared_handle.h:898
Cgu::GSliceFree::operator()
void operator()(T obj) noexcept
Definition: shared_handle.h:315
Cgu::SharedHandle::SharedHandle
SharedHandle(const SharedHandle &sh_hand) noexcept
Definition: shared_handle.h:730
Cgu::ScopedHandle::ScopedHandle
ScopedHandle(ScopedHandle &&sc_hand) noexcept
Definition: shared_handle.h:849
Cgu::CFree::operator()
void operator()(const void *obj) noexcept
Definition: shared_handle.h:252
Cgu::GFree::operator()
void operator()(const void *obj) noexcept
Definition: shared_handle.h:272
Cgu::operator<
bool operator<(const GobjHandle< T > &h1, const GobjHandle< T > &h2)
Definition: gobj_handle.h:632
Cgu::operator!=
bool operator!=(const GobjHandle< T > &h1, const GobjHandle< T > &h2) noexcept
Definition: gobj_handle.h:613
Cgu::SharedLockHandle::operator=
SharedLockHandle & operator=(SharedLockHandle sh_hand)
Definition: shared_handle.h:1419
Cgu::SharedLockHandle::SharedLockHandle
SharedLockHandle(SharedLockHandle &&sh_hand) noexcept
Definition: shared_handle.h:1401
Cgu::SharedHandle::SharedHandle
SharedHandle(T ptr=0)
Definition: shared_handle.h:592
Cgu::swap
void swap(Cgu::AsyncQueue< T, Container > &q1, Cgu::AsyncQueue< T, Container > &q2)
Definition: async_queue.h:1493
Cgu::SharedHandleError::SharedHandleError
SharedHandleError(T p)
Definition: shared_handle.h:528
Cgu::GSliceFreeSize
A deleter functor for use as the second (Dealloc) template parameter of the SharedHandle,...
Definition: shared_handle.h:421
Cgu::SharedHandleAllocFail::leave
@ leave
Definition: shared_handle.h:541
Cgu::SharedLockHandle
This is a generic class for managing the lifetime of objects allocated on freestore,...
Definition: shared_handle.h:1059
Cgu::GSliceFreeSize::operator()
void operator()(const void *obj) noexcept
Definition: shared_handle.h:423
Cgu::SharedHandle::operator=
SharedHandle & operator=(SharedHandle sh_hand)
Definition: shared_handle.h:755
Cgu::GSliceDestroy::operator()
void operator()(T obj)
Definition: shared_handle.h:383
Cgu::SharedHandle
This is a generic class for managing the lifetime of objects allocated on freestore.
Definition: shared_handle.h:451
Cgu::ScopedHandle::ScopedHandle
ScopedHandle(const ScopedHandle &)=delete
Cgu::ScopedHandle::ScopedHandle
ScopedHandle(T ptr=0) noexcept
Definition: shared_handle.h:877
Cgu::StandardArrayDelete
A deleter functor for use as the second (Dealloc) template parameter of the SharedHandle,...
Definition: shared_handle.h:232
Cgu::SharedLockHandle::get_refcount
unsigned int get_refcount() const noexcept
Definition: shared_handle.h:1447
Cgu::operator==
bool operator==(const GobjHandle< T > &h1, const GobjHandle< T > &h2) noexcept
Definition: gobj_handle.h:600
Cgu::ScopedHandle::operator=
ScopedHandle & operator=(const ScopedHandle &)=delete
Cgu::SharedHandle::~SharedHandle
~SharedHandle()
Definition: shared_handle.h:785
Cgu::Thread::Mutex::Lock
A scoped locking class for exception safe Mutex locking.
Definition: mutex.h:207
Cgu::SharedHandle::SharedHandle
SharedHandle(SharedHandle &&sh_hand) noexcept
Definition: shared_handle.h:739
Cgu::ScopedHandle::reset
void reset(T ptr=0)
Definition: shared_handle.h:887
hash
A specialization of std::hash for Cgu::Callback::FunctorArg, Cgu::Callback::SafeFunctorArg,...
Cgu::GSliceFree
A deleter functor for use as the second (Dealloc) template parameter of the SharedHandle,...
Definition: shared_handle.h:313
mutex.h
Provides wrapper classes for pthread mutexes and condition variables, and scoped locking classes for ...
Cgu::ScopedHandle::operator=
ScopedHandle & operator=(ScopedHandle &&sc_hand)
Definition: shared_handle.h:863
Cgu::SharedHandleError::what
virtual const char * what() const
Definition: shared_handle.h:527
Cgu::SharedLockHandle::~SharedLockHandle
~SharedLockHandle()
Definition: shared_handle.h:1461
Cgu::ScopedHandle
This is a generic scoped class for managing the lifetime of objects allocated on freestore.
Definition: shared_handle.h:452
Cgu::SharedHandleAllocFail::Leave
Leave
Definition: shared_handle.h:541
Cgu::SharedHandleError::obj
T obj
Definition: shared_handle.h:526
Cgu::Thread::MutexError
Definition: mutex.h:81
Cgu::SharedHandle::get
T get() const noexcept
Definition: shared_handle.h:765
Cgu::SharedLockHandle::SharedLockHandle
SharedLockHandle(const SharedLockHandle &sh_hand) noexcept
Definition: shared_handle.h:1392
Cgu::SharedHandle::reset
void reset(T ptr, Cgu::SharedHandleAllocFail::Leave tag)
Definition: shared_handle.h:721
Cgu::SharedLockHandle::SharedLockHandle
SharedLockHandle(T ptr=0)
Definition: shared_handle.h:1154
Cgu::Thread::Mutex
A wrapper class for pthread mutexes.
Definition: mutex.h:117
cgu_config.h
Cgu::SharedLockHandle::SharedLockHandle
SharedLockHandle(T ptr, Cgu::SharedHandleAllocFail::Leave tag)
Definition: shared_handle.h:1242
Cgu::SharedLockHandle::reset
void reset(T ptr=0)
Definition: shared_handle.h:1327