deal.II version GIT relicensing-2220-ge8e5360a96 2024-12-05 09:50: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\}}\)
Loading...
Searching...
No Matches
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 <typeinfo>
26
28
104template <typename T, typename P = void>
106{
107public:
113
118 template <class Q>
120
126
131
141 ObserverPointer(T *t, const std::string &id);
142
150
155
163 operator=(T *tt);
164
169 template <class Q>
172
179
185
197 void
199
203 operator T *() const;
204
209 T &
210 operator*() const;
211
216 T *
217 get() const;
218
223 T *
224 operator->() const;
225
235 template <class Q>
236 void
238
247 void
248 swap(T *&ptr);
249
255 std::size_t
257
258private:
263
267 const std::string id;
268
273 std::atomic<bool> pointed_to_object_is_alive;
274};
275
276
283template <typename T, typename P = void>
284using SmartPointer DEAL_II_DEPRECATED_EARLY_WITH_COMMENT(
285 "Use the new name of the class, ObserverPointer.") = ObserverPointer<T, P>;
286
287
288/* --------------------- inline Template functions ------------------------- */
289
290
291template <typename T, typename P>
293 : pointer(nullptr)
294 , id(typeid(P).name())
295 , pointed_to_object_is_alive(false)
296{
297 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
298 "This class can only be used if the first template argument "
299 "is a class derived from 'EnableObserverPointer'.");
300}
301
302
303
304template <typename T, typename P>
306 : pointer(t)
307 , id(typeid(P).name())
308 , pointed_to_object_is_alive(false)
309{
310 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
311 "This class can only be used if the first template argument "
312 "is a class derived from 'EnableObserverPointer'.");
313
314 if (t != nullptr)
315 t->subscribe(&pointed_to_object_is_alive, id);
316}
317
318
319
320template <typename T, typename P>
321inline ObserverPointer<T, P>::ObserverPointer(T *t, const std::string &id)
322 : pointer(t)
323 , id(id)
324 , pointed_to_object_is_alive(false)
325{
326 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
327 "This class can only be used if the first template argument "
328 "is a class derived from 'EnableObserverPointer'.");
329
330 if (pointer != nullptr)
331 pointer->subscribe(&pointed_to_object_is_alive, id);
332}
333
334
335
336template <typename T, typename P>
337template <class Q>
339 const ObserverPointer<T, Q> &other)
340 : pointer(other.pointer)
341 , id(other.id)
342 , pointed_to_object_is_alive(false)
343{
344 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
345 "This class can only be used if the first template argument "
346 "is a class derived from 'EnableObserverPointer'.");
347
348 if (other != nullptr)
349 {
351 ExcMessage("You can't copy a smart pointer object that "
352 "is pointing to an object that is no longer alive."));
353 pointer->subscribe(&pointed_to_object_is_alive, id);
354 }
355}
356
357
358
359template <typename T, typename P>
361 const ObserverPointer<T, P> &other)
362 : pointer(other.pointer)
363 , id(other.id)
364 , pointed_to_object_is_alive(false)
365{
366 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
367 "This class can only be used if the first template argument "
368 "is a class derived from 'EnableObserverPointer'.");
369
370 if (other != nullptr)
371 {
373 ExcMessage("You can't copy a smart pointer object that "
374 "is pointing to an object that is no longer alive."));
375 pointer->subscribe(&pointed_to_object_is_alive, id);
376 }
377}
378
379
380
381template <typename T, typename P>
383 ObserverPointer<T, P> &&other) noexcept
384 : pointer(other.pointer)
385 , id(other.id)
386 , pointed_to_object_is_alive(false)
387{
388 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
389 "This class can only be used if the first template argument "
390 "is a class derived from 'EnableObserverPointer'.");
391
392 if (other != nullptr)
393 {
394 Assert(other.pointed_to_object_is_alive,
395 ExcMessage("You can't move a smart pointer object that "
396 "is pointing to an object that is no longer alive."));
397
398 try
399 {
400 pointer->subscribe(&pointed_to_object_is_alive, id);
401 }
402 catch (...)
403 {
404 Assert(false,
406 "Calling subscribe() failed with an exception, but we "
407 "are in a function that cannot throw exceptions. "
408 "Aborting the program here."));
409 }
410
411 // Release the rhs object as if we had moved all members away from
412 // it directly:
413 other = nullptr;
414 }
415}
416
417
418
419template <typename T, typename P>
421{
422 static_assert(std::is_base_of_v<EnableObserverPointer, T>,
423 "This class can only be used if the first template argument "
424 "is a class derived from 'EnableObserverPointer'.");
425
426 if (pointed_to_object_is_alive && pointer != nullptr)
427 pointer->unsubscribe(&pointed_to_object_is_alive, id);
428}
429
430
431
432template <typename T, typename P>
433inline void
435{
436 if (pointed_to_object_is_alive && pointer != nullptr)
437 {
438 pointer->unsubscribe(&pointed_to_object_is_alive, id);
439 delete pointer;
440 Assert(pointed_to_object_is_alive == false, ExcInternalError());
441 }
442 pointer = nullptr;
443}
444
445
446
447template <typename T, typename P>
450{
451 // optimize if no real action is requested
452 if (pointer == tt)
453 return *this;
454
455 // Let us unsubscribe from the current object
456 if (pointed_to_object_is_alive && pointer != nullptr)
457 pointer->unsubscribe(&pointed_to_object_is_alive, id);
458
459 // Then reset to the new object, and subscribe to it
460 pointer = tt;
461 if (tt != nullptr)
462 pointer->subscribe(&pointed_to_object_is_alive, id);
463
464 return *this;
465}
466
467
468
469template <typename T, typename P>
470template <class Q>
473{
474 // if objects on the left and right
475 // hand side of the operator= are
476 // the same, then this is a no-op
477 if (&other == this)
478 return *this;
479
480 // Let us unsubscribe from the current object
481 if (pointed_to_object_is_alive && pointer != nullptr)
482 pointer->unsubscribe(&pointed_to_object_is_alive, id);
483
484 // Then reset to the new object, and subscribe to it
485 pointer = (other != nullptr ? other.get() : nullptr);
486 if (other != nullptr)
487 {
489 ExcMessage("You can't copy a smart pointer object that "
490 "is pointing to an object that is no longer alive."));
491 pointer->subscribe(&pointed_to_object_is_alive, id);
492 }
493 return *this;
494}
495
496
497
498template <typename T, typename P>
501{
502 // if objects on the left and right
503 // hand side of the operator= are
504 // the same, then this is a no-op
505 if (&other == this)
506 return *this;
507
508 // Let us unsubscribe from the current object
509 if (pointed_to_object_is_alive && pointer != nullptr)
510 pointer->unsubscribe(&pointed_to_object_is_alive, id);
511
512 // Then reset to the new object, and subscribe to it
513 pointer = (other != nullptr ? other.get() : nullptr);
514 if (other != nullptr)
515 {
517 ExcMessage("You can't copy a smart pointer object that "
518 "is pointing to an object that is no longer alive."));
519 pointer->subscribe(&pointed_to_object_is_alive, id);
520 }
521 return *this;
522}
523
524
525
526template <typename T, typename P>
529{
530 if (other == nullptr)
531 {
532 *this = nullptr;
533 }
534 // if objects on the left and right hand side of the operator= are
535 // the same, then this is a no-op
536 else if (&other != this)
537 {
538 // Let us unsubscribe from the current object
539 if (pointer != nullptr && pointed_to_object_is_alive)
540 pointer->unsubscribe(&pointed_to_object_is_alive, id);
541
542 // Then reset to the new object, and subscribe to it:
543 Assert(other.pointed_to_object_is_alive,
544 ExcMessage("You can't move a smart pointer object that "
545 "is pointing to an object that is no longer alive."));
546 pointer = other.get();
547 try
548 {
549 pointer->subscribe(&pointed_to_object_is_alive, id);
550 }
551 catch (...)
552 {
553 Assert(false,
555 "Calling subscribe() failed with an exception, but we "
556 "are in a function that cannot throw exceptions. "
557 "Aborting the program here."));
558 }
559
560 // Finally release the rhs object since we moved its contents
561 other = nullptr;
562 }
563 return *this;
564}
565
566
567
568template <typename T, typename P>
570{
571 return pointer;
572}
573
574
575
576template <typename T, typename P>
577inline T &
579{
580 Assert(pointer != nullptr, ExcNotInitialized());
581 Assert(pointed_to_object_is_alive,
582 ExcMessage("The object pointed to is not valid anymore."));
583 return *pointer;
584}
585
586
587
588template <typename T, typename P>
589inline T *
591{
592 Assert(pointer != nullptr, ExcNotInitialized());
593 Assert(pointed_to_object_is_alive,
594 ExcMessage("The object pointed to is not valid anymore."));
595 return pointer;
596}
597
598
599
600template <typename T, typename P>
601inline T *
603{
604 return this->get();
605}
606
607
608
609template <typename T, typename P>
610template <class Q>
611inline void
613{
614#ifdef DEBUG
615 ObserverPointer<T, P> aux(pointer, id);
616 *this = other;
617 other = aux;
618#else
619 std::swap(pointer, other.pointer);
620#endif
621}
622
623
624
625template <typename T, typename P>
626inline void
628{
629 if (pointed_to_object_is_alive && pointer != nullptr)
630 pointer->unsubscribe(pointed_to_object_is_alive, id);
631
632 std::swap(pointer, ptr);
633
634 if (pointer != nullptr)
635 pointer->subscribe(pointed_to_object_is_alive, id);
636}
637
638
639
640template <typename T, typename P>
641inline std::size_t
646
647
648
649// The following function is not strictly necessary but is an optimization
650// for places where you call swap(p1,p2) with ObserverPointer objects p1, p2.
651// Unfortunately, MS Visual Studio (at least up to the 2013 edition) trips
652// over it when calling std::swap(v1,v2) where v1,v2 are std::vectors of
653// ObserverPointer objects: it can't determine whether it should call std::swap
654// or ::swap on the individual elements (see bug #184 on our Google Code
655// site. Consequently, just take this function out of the competition for this
656// compiler.
657#ifndef _MSC_VER
663template <typename T, typename P, class Q>
664inline void
666{
667 t1.swap(t2);
668}
669#endif
670
671
679template <typename T, typename P>
680inline void
682{
683 t1.swap(t2);
684}
685
686
687
695template <typename T, typename P>
696inline void
698{
699 t2.swap(t1);
700}
701
703
704#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:205
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:498
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:499
#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)