Loading [MathJax]/extensions/TeX/AMSsymbols.js
 deal.II version GIT relicensing-3041-g9c4075ddf4 2025-04-07 16:30:00+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
observer_pointer.h
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 1998 - 2023 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_observer_pointer_h
16#define dealii_observer_pointer_h
17
18
19#include <deal.II/base/config.h>
20
23
24#include <atomic>
25#include <string>
26#include <typeinfo>
27
29
105template <typename T, typename P = void>
107{
108public:
114
119 template <class Q>
121
127
132
142 ObserverPointer(T *t, const std::string &id);
143
151
156
164 operator=(T *tt);
165
170 template <class Q>
173
180
186
198 void
200
204 operator T *() const;
205
210 T &
211 operator*() const;
212
217 T *
218 get() const;
219
224 T *
225 operator->() const;
226
236 template <class Q>
237 void
239
248 void
249 swap(T *&ptr);
250
256 std::size_t
258
259private:
264
268 const std::string id;
269
274 std::atomic<bool> pointed_to_object_is_alive;
275};
276
277
284template <typename T, typename P = void>
285using SmartPointer DEAL_II_DEPRECATED_EARLY_WITH_COMMENT(
286 "Use the new name of the class, ObserverPointer.") = ObserverPointer<T, P>;
287
288
289/* --------------------- inline Template functions ------------------------- */
290
291
292template <typename T, typename P>
294 : pointer(nullptr)
295 , id(typeid(P).name())
296 , pointed_to_object_is_alive(false)
297{
298 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
299 "This class can only be used if the first template argument "
300 "is a class derived from 'EnableObserverPointer'.");
301}
302
303
304
305template <typename T, typename P>
307 : pointer(t)
308 , id(typeid(P).name())
309 , pointed_to_object_is_alive(false)
310{
311 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
312 "This class can only be used if the first template argument "
313 "is a class derived from 'EnableObserverPointer'.");
314
315 if (t != nullptr)
316 t->subscribe(&pointed_to_object_is_alive, id);
317}
318
319
320
321template <typename T, typename P>
322inline ObserverPointer<T, P>::ObserverPointer(T *t, const std::string &id)
323 : pointer(t)
324 , id(id)
325 , pointed_to_object_is_alive(false)
326{
327 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
328 "This class can only be used if the first template argument "
329 "is a class derived from 'EnableObserverPointer'.");
330
331 if (pointer != nullptr)
332 pointer->subscribe(&pointed_to_object_is_alive, id);
333}
334
335
336
337template <typename T, typename P>
338template <class Q>
340 const ObserverPointer<T, Q> &other)
341 : pointer(other.pointer)
342 , id(other.id)
343 , pointed_to_object_is_alive(false)
344{
345 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
346 "This class can only be used if the first template argument "
347 "is a class derived from 'EnableObserverPointer'.");
348
349 if (other != nullptr)
350 {
352 ExcMessage("You can't copy a smart pointer object that "
353 "is pointing to an object that is no longer alive."));
354 pointer->subscribe(&pointed_to_object_is_alive, id);
355 }
356}
357
358
359
360template <typename T, typename P>
362 const ObserverPointer<T, P> &other)
363 : pointer(other.pointer)
364 , id(other.id)
365 , pointed_to_object_is_alive(false)
366{
367 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
368 "This class can only be used if the first template argument "
369 "is a class derived from 'EnableObserverPointer'.");
370
371 if (other != nullptr)
372 {
374 ExcMessage("You can't copy a smart pointer object that "
375 "is pointing to an object that is no longer alive."));
376 pointer->subscribe(&pointed_to_object_is_alive, id);
377 }
378}
379
380
381
382template <typename T, typename P>
384 ObserverPointer<T, P> &&other) noexcept
385 : pointer(other.pointer)
386 , id(other.id)
387 , pointed_to_object_is_alive(false)
388{
389 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
390 "This class can only be used if the first template argument "
391 "is a class derived from 'EnableObserverPointer'.");
392
393 if (other != nullptr)
394 {
395 Assert(other.pointed_to_object_is_alive,
396 ExcMessage("You can't move a smart pointer object that "
397 "is pointing to an object that is no longer alive."));
398
399 try
400 {
401 pointer->subscribe(&pointed_to_object_is_alive, id);
402 }
403 catch (...)
404 {
405 Assert(false,
407 "Calling subscribe() failed with an exception, but we "
408 "are in a function that cannot throw exceptions. "
409 "Aborting the program here."));
410 }
411
412 // Release the rhs object as if we had moved all members away from
413 // it directly:
414 other = nullptr;
415 }
416}
417
418
419
420template <typename T, typename P>
422{
423 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
424 "This class can only be used if the first template argument "
425 "is a class derived from 'EnableObserverPointer'.");
426
427 if (pointed_to_object_is_alive && pointer != nullptr)
428 pointer->unsubscribe(&pointed_to_object_is_alive, id);
429}
430
431
432
433template <typename T, typename P>
434inline void
436{
437 if (pointed_to_object_is_alive && pointer != nullptr)
438 {
439 pointer->unsubscribe(&pointed_to_object_is_alive, id);
440 delete pointer;
441 Assert(pointed_to_object_is_alive == false, ExcInternalError());
442 }
443 pointer = nullptr;
444}
445
446
447
448template <typename T, typename P>
451{
452 // optimize if no real action is requested
453 if (pointer == tt)
454 return *this;
455
456 // Let us unsubscribe from the current object
457 if (pointed_to_object_is_alive && pointer != nullptr)
458 pointer->unsubscribe(&pointed_to_object_is_alive, id);
459
460 // Then reset to the new object, and subscribe to it
461 pointer = tt;
462 if (tt != nullptr)
463 pointer->subscribe(&pointed_to_object_is_alive, id);
464
465 return *this;
466}
467
468
469
470template <typename T, typename P>
471template <class Q>
474{
475 // if objects on the left and right
476 // hand side of the operator= are
477 // the same, then this is a no-op
478 if (&other == this)
479 return *this;
480
481 // Let us unsubscribe from the current object
482 if (pointed_to_object_is_alive && pointer != nullptr)
483 pointer->unsubscribe(&pointed_to_object_is_alive, id);
484
485 // Then reset to the new object, and subscribe to it
486 pointer = (other != nullptr ? other.get() : nullptr);
487 if (other != nullptr)
488 {
490 ExcMessage("You can't copy a smart pointer object that "
491 "is pointing to an object that is no longer alive."));
492 pointer->subscribe(&pointed_to_object_is_alive, id);
493 }
494 return *this;
495}
496
497
498
499template <typename T, typename P>
502{
503 // if objects on the left and right
504 // hand side of the operator= are
505 // the same, then this is a no-op
506 if (&other == this)
507 return *this;
508
509 // Let us unsubscribe from the current object
510 if (pointed_to_object_is_alive && pointer != nullptr)
511 pointer->unsubscribe(&pointed_to_object_is_alive, id);
512
513 // Then reset to the new object, and subscribe to it
514 pointer = (other != nullptr ? other.get() : nullptr);
515 if (other != nullptr)
516 {
518 ExcMessage("You can't copy a smart pointer object that "
519 "is pointing to an object that is no longer alive."));
520 pointer->subscribe(&pointed_to_object_is_alive, id);
521 }
522 return *this;
523}
524
525
526
527template <typename T, typename P>
530{
531 if (other == nullptr)
532 {
533 *this = nullptr;
534 }
535 // if objects on the left and right hand side of the operator= are
536 // the same, then this is a no-op
537 else if (&other != this)
538 {
539 // Let us unsubscribe from the current object
540 if (pointer != nullptr && pointed_to_object_is_alive)
541 pointer->unsubscribe(&pointed_to_object_is_alive, id);
542
543 // Then reset to the new object, and subscribe to it:
544 Assert(other.pointed_to_object_is_alive,
545 ExcMessage("You can't move a smart pointer object that "
546 "is pointing to an object that is no longer alive."));
547 pointer = other.get();
548 try
549 {
550 pointer->subscribe(&pointed_to_object_is_alive, id);
551 }
552 catch (...)
553 {
554 Assert(false,
556 "Calling subscribe() failed with an exception, but we "
557 "are in a function that cannot throw exceptions. "
558 "Aborting the program here."));
559 }
560
561 // Finally release the rhs object since we moved its contents
562 other = nullptr;
563 }
564 return *this;
565}
566
567
568
569template <typename T, typename P>
571{
572 return pointer;
573}
574
575
576
577template <typename T, typename P>
578inline T &
580{
581 Assert(pointer != nullptr, ExcNotInitialized());
582 Assert(pointed_to_object_is_alive,
583 ExcMessage("The object pointed to is not valid anymore."));
584 return *pointer;
585}
586
587
588
589template <typename T, typename P>
590inline T *
592{
593 Assert(pointer != nullptr, ExcNotInitialized());
594 Assert(pointed_to_object_is_alive,
595 ExcMessage("The object pointed to is not valid anymore."));
596 return pointer;
597}
598
599
600
601template <typename T, typename P>
602inline T *
604{
605 return this->get();
606}
607
608
609
610template <typename T, typename P>
611template <class Q>
612inline void
614{
615 if constexpr (running_in_debug_mode())
616 {
617 ObserverPointer<T, P> aux(pointer, id);
618 *this = other;
619 other = aux;
620 }
621 else
622 {
623 std::swap(pointer, other.pointer);
624 }
625}
626
627
628
629template <typename T, typename P>
630inline void
632{
633 if (pointed_to_object_is_alive && pointer != nullptr)
634 pointer->unsubscribe(pointed_to_object_is_alive, id);
635
636 std::swap(pointer, ptr);
637
638 if (pointer != nullptr)
639 pointer->subscribe(pointed_to_object_is_alive, id);
640}
641
642
643
644template <typename T, typename P>
645inline std::size_t
650
651
652
653// The following function is not strictly necessary but is an optimization
654// for places where you call swap(p1,p2) with ObserverPointer objects p1, p2.
655// Unfortunately, MS Visual Studio (at least up to the 2013 edition) trips
656// over it when calling std::swap(v1,v2) where v1,v2 are std::vectors of
657// ObserverPointer objects: it can't determine whether it should call std::swap
658// or ::swap on the individual elements (see bug #184 on our Google Code
659// site. Consequently, just take this function out of the competition for this
660// compiler.
661#ifndef _MSC_VER
667template <typename T, typename P, class Q>
668inline void
670{
671 t1.swap(t2);
672}
673#endif
674
675
683template <typename T, typename P>
684inline void
686{
687 t1.swap(t2);
688}
689
690
691
699template <typename T, typename P>
700inline void
702{
703 t2.swap(t1);
704}
705
707
708#endif
T & operator*() const
void swap(T *&ptr)
std::size_t memory_consumption() const
T * operator->() const
void swap(ObserverPointer< T, Q > &tt)
std::atomic< bool > pointed_to_object_is_alive
ObserverPointer< T, P > & operator=(const ObserverPointer< T, P > &other)
ObserverPointer< T, P > & operator=(const ObserverPointer< T, Q > &other)
ObserverPointer(const ObserverPointer< T, P > &other)
const std::string id
ObserverPointer< T, P > & operator=(T *tt)
ObserverPointer< T, P > & operator=(ObserverPointer< T, P > &&other) noexcept
ObserverPointer(const ObserverPointer< T, Q > &other)
ObserverPointer(ObserverPointer< T, P > &&other) noexcept
ObserverPointer(T *t, const std::string &id)
#define DEAL_II_DEPRECATED
Definition config.h:280
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:35
constexpr bool running_in_debug_mode()
Definition config.h:73
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:36
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcNotInitialized()
static ::ExceptionBase & ExcMessage(std::string arg1)
void swap(ObserverPointer< T, P > &t1, ObserverPointer< T, Q > &t2)