deal.II version 9.8.0
\(\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\}}\)
Loading...
Searching...
No Matches
observer_pointer.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 1998 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_observer_pointer_h
14#define dealii_observer_pointer_h
15
16
17#include <deal.II/base/config.h>
18
21
22#include <atomic>
23#include <string>
24#include <typeinfo>
25
27
103template <typename T, typename P = void>
105{
106public:
112
117 template <class Q>
119
125
130
140 ObserverPointer(T *t, const std::string &id);
141
149
154
162 operator=(T *tt);
163
168 template <class Q>
171
178
184
196 void
198
202 operator T *() const;
203
208 T &
209 operator*() const;
210
215 T *
216 get() const;
217
222 T *
223 operator->() const;
224
234 template <class Q>
235 void
237
246 void
247 swap(T *&ptr);
248
254 std::size_t
256
257private:
262
266 const std::string id;
267
272 std::atomic<bool> pointed_to_object_is_alive;
273};
274
275
282template <typename T, typename P = void>
284 "Use the new name of the class, ObserverPointer.") = ObserverPointer<T, P>;
285
286
287/* --------------------- inline Template functions ------------------------- */
288
289
290template <typename T, typename P>
292 : pointer(nullptr)
293 , id(typeid(P).name())
295{
296 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
297 "This class can only be used if the first template argument "
298 "is a class derived from 'EnableObserverPointer'.");
299}
300
301
302
303template <typename T, typename P>
305 : pointer(t)
306 , id(typeid(P).name())
308{
309 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
310 "This class can only be used if the first template argument "
311 "is a class derived from 'EnableObserverPointer'.");
312
313 if (t != nullptr)
314 t->subscribe(&pointed_to_object_is_alive, id);
315}
316
317
318
319template <typename T, typename P>
320inline ObserverPointer<T, P>::ObserverPointer(T *t, const std::string &id)
321 : pointer(t)
322 , id(id)
324{
325 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
326 "This class can only be used if the first template argument "
327 "is a class derived from 'EnableObserverPointer'.");
328
329 if (pointer != nullptr)
330 pointer->subscribe(&pointed_to_object_is_alive, id);
331}
332
333
334
335template <typename T, typename P>
336template <class Q>
338 const ObserverPointer<T, Q> &other)
339 : pointer(other.pointer)
340 , id(other.id)
342{
343 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
344 "This class can only be used if the first template argument "
345 "is a class derived from 'EnableObserverPointer'.");
346
347 if (other != nullptr)
348 {
350 ExcMessage("You can't copy a smart pointer object that "
351 "is pointing to an object that is no longer alive."));
352 pointer->subscribe(&pointed_to_object_is_alive, id);
353 }
354}
355
356
357
358template <typename T, typename P>
360 const ObserverPointer<T, P> &other)
361 : pointer(other.pointer)
362 , id(other.id)
364{
365 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
366 "This class can only be used if the first template argument "
367 "is a class derived from 'EnableObserverPointer'.");
368
369 if (other != nullptr)
370 {
372 ExcMessage("You can't copy a smart pointer object that "
373 "is pointing to an object that is no longer alive."));
374 pointer->subscribe(&pointed_to_object_is_alive, id);
375 }
376}
377
378
379
380template <typename T, typename P>
382 ObserverPointer<T, P> &&other) noexcept
383 : pointer(other.pointer)
384 , id(other.id)
386{
387 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
388 "This class can only be used if the first template argument "
389 "is a class derived from 'EnableObserverPointer'.");
390
391 if (other != nullptr)
392 {
393 Assert(other.pointed_to_object_is_alive,
394 ExcMessage("You can't move a smart pointer object that "
395 "is pointing to an object that is no longer alive."));
396
397 try
398 {
399 pointer->subscribe(&pointed_to_object_is_alive, id);
400 }
401 catch (...)
402 {
403 Assert(false,
405 "Calling subscribe() failed with an exception, but we "
406 "are in a function that cannot throw exceptions. "
407 "Aborting the program here."));
408 }
409
410 // Release the rhs object as if we had moved all members away from
411 // it directly:
412 other = nullptr;
413 }
414}
415
416
417
418template <typename T, typename P>
420{
421 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
422 "This class can only be used if the first template argument "
423 "is a class derived from 'EnableObserverPointer'.");
424
425 if (pointed_to_object_is_alive && pointer != nullptr)
426 pointer->unsubscribe(&pointed_to_object_is_alive, id);
427}
428
429
430
431template <typename T, typename P>
432inline void
434{
435 if (pointed_to_object_is_alive && pointer != nullptr)
436 {
437 pointer->unsubscribe(&pointed_to_object_is_alive, id);
438 delete pointer;
440 }
441 pointer = nullptr;
442}
443
444
445
446template <typename T, typename P>
449{
450 // optimize if no real action is requested
451 if (pointer == tt)
452 return *this;
453
454 // Let us unsubscribe from the current object
455 if (pointed_to_object_is_alive && pointer != nullptr)
456 pointer->unsubscribe(&pointed_to_object_is_alive, id);
457
458 // Then reset to the new object, and subscribe to it
459 pointer = tt;
460 if (tt != nullptr)
461 pointer->subscribe(&pointed_to_object_is_alive, id);
462
463 return *this;
464}
465
466
467
468template <typename T, typename P>
469template <class Q>
472{
473 // if objects on the left and right
474 // hand side of the operator= are
475 // the same, then this is a no-op
476 if (&other == this)
477 return *this;
478
479 // Let us unsubscribe from the current object
480 if (pointed_to_object_is_alive && pointer != nullptr)
481 pointer->unsubscribe(&pointed_to_object_is_alive, id);
482
483 // Then reset to the new object, and subscribe to it
484 pointer = (other != nullptr ? other.get() : nullptr);
485 if (other != nullptr)
486 {
488 ExcMessage("You can't copy a smart pointer object that "
489 "is pointing to an object that is no longer alive."));
490 pointer->subscribe(&pointed_to_object_is_alive, id);
491 }
492 return *this;
493}
494
495
496
497template <typename T, typename P>
500{
501 // if objects on the left and right
502 // hand side of the operator= are
503 // the same, then this is a no-op
504 if (&other == this)
505 return *this;
506
507 // Let us unsubscribe from the current object
508 if (pointed_to_object_is_alive && pointer != nullptr)
509 pointer->unsubscribe(&pointed_to_object_is_alive, id);
510
511 // Then reset to the new object, and subscribe to it
512 pointer = (other != nullptr ? other.get() : nullptr);
513 if (other != nullptr)
514 {
516 ExcMessage("You can't copy a smart pointer object that "
517 "is pointing to an object that is no longer alive."));
518 pointer->subscribe(&pointed_to_object_is_alive, id);
519 }
520 return *this;
521}
522
523
524
525template <typename T, typename P>
528{
529 if (other == nullptr)
530 {
531 *this = nullptr;
532 }
533 // if objects on the left and right hand side of the operator= are
534 // the same, then this is a no-op
535 else if (&other != this)
536 {
537 // Let us unsubscribe from the current object
538 if (pointer != nullptr && pointed_to_object_is_alive)
539 pointer->unsubscribe(&pointed_to_object_is_alive, id);
540
541 // Then reset to the new object, and subscribe to it:
542 Assert(other.pointed_to_object_is_alive,
543 ExcMessage("You can't move a smart pointer object that "
544 "is pointing to an object that is no longer alive."));
545 pointer = other.get();
546 try
547 {
548 pointer->subscribe(&pointed_to_object_is_alive, id);
549 }
550 catch (...)
551 {
552 Assert(false,
554 "Calling subscribe() failed with an exception, but we "
555 "are in a function that cannot throw exceptions. "
556 "Aborting the program here."));
557 }
558
559 // Finally release the rhs object since we moved its contents
560 other = nullptr;
561 }
562 return *this;
563}
564
565
566
567template <typename T, typename P>
568inline ObserverPointer<T, P>::operator T *() const
569{
570 return pointer;
571}
572
573
574
575template <typename T, typename P>
576inline T &
578{
579 Assert(pointer != nullptr, ExcNotInitialized());
581 ExcMessage("The object pointed to is not valid anymore."));
582 return *pointer;
583}
584
585
586
587template <typename T, typename P>
588inline T *
590{
591 Assert(pointer != nullptr, ExcNotInitialized());
593 ExcMessage("The object pointed to is not valid anymore."));
594 return pointer;
595}
596
597
598
599template <typename T, typename P>
600inline T *
602{
603 return this->get();
604}
605
606
607
608template <typename T, typename P>
609template <class Q>
610inline void
612{
613 if constexpr (running_in_debug_mode())
614 {
616 *this = other;
617 other = aux;
618 }
619 else
620 {
621 std::swap(pointer, other.pointer);
622 }
623}
624
625
626
627template <typename T, typename P>
628inline void
630{
631 if (pointed_to_object_is_alive && pointer != nullptr)
632 pointer->unsubscribe(pointed_to_object_is_alive, id);
633
634 std::swap(pointer, ptr);
635
636 if (pointer != nullptr)
637 pointer->subscribe(pointed_to_object_is_alive, id);
638}
639
640
641
642template <typename T, typename P>
643inline std::size_t
645{
646 return sizeof(ObserverPointer<T, P>);
647}
648
649
650
651// The following function is not strictly necessary but is an optimization
652// for places where you call swap(p1,p2) with ObserverPointer objects p1, p2.
653// Unfortunately, MS Visual Studio (at least up to the 2013 edition) trips
654// over it when calling std::swap(v1,v2) where v1,v2 are std::vectors of
655// ObserverPointer objects: it can't determine whether it should call std::swap
656// or ::swap on the individual elements (see bug #184 on our Google Code
657// site. Consequently, just take this function out of the competition for this
658// compiler.
659#ifndef _MSC_VER
665template <typename T, typename P, class Q>
666inline void
668{
669 t1.swap(t2);
670}
671#endif
672
673
681template <typename T, typename P>
682inline void
683swap(ObserverPointer<T, P> &t1, T *&t2)
684{
685 t1.swap(t2);
686}
687
688
689
697template <typename T, typename P>
698inline void
699swap(T *&t1, ObserverPointer<T, P> &t2)
700{
701 t2.swap(t1);
702}
703
705
706#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)
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:286
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_DEPRECATED_WITH_COMMENT(comment)
Definition config.h:287
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcNotInitialized()
static ::ExceptionBase & ExcMessage(std::string arg1)
ObserverPointer< T, P > SmartPointer
void swap(ObserverPointer< T, P > &t1, ObserverPointer< T, Q > &t2)