deal.II version GIT relicensing-1900-g3b182cc6ca 2024-09-26 19: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
103template <typename T, typename P = void>
105{
106public:
112
117 template <class Q>
119
125
130
139 ObserverPointer(T *t, const std::string &id);
140
148
153
161 operator=(T *tt);
162
167 template <class Q>
170
177
183
195 void
197
201 operator T *() const;
202
207 T &
208 operator*() const;
209
214 T *
215 get() const;
216
221 T *
222 operator->() const;
223
233 template <class Q>
234 void
236
245 void
246 swap(T *&ptr);
247
253 std::size_t
255
256private:
261
265 const std::string id;
266
271 std::atomic<bool> pointed_to_object_is_alive;
272};
273
274
281template <typename T, typename P = void>
282using SmartPointer DEAL_II_DEPRECATED_EARLY_WITH_COMMENT(
283 "Use the new name of the class, ObserverPointer.") = ObserverPointer<T, P>;
284
285
286/* --------------------- inline Template functions ------------------------- */
287
288
289template <typename T, typename P>
291 : pointer(nullptr)
292 , id(typeid(P).name())
293 , pointed_to_object_is_alive(false)
294{
295 static_assert(std::is_base_of_v<Subscriptor, T>,
296 "This class can only be used if the first template argument "
297 "is a class derived from 'Subscriptor'.");
298}
299
300
301
302template <typename T, typename P>
304 : pointer(t)
305 , id(typeid(P).name())
306 , pointed_to_object_is_alive(false)
307{
308 static_assert(std::is_base_of_v<Subscriptor, T>,
309 "This class can only be used if the first template argument "
310 "is a class derived from 'Subscriptor'.");
311
312 if (t != nullptr)
313 t->subscribe(&pointed_to_object_is_alive, id);
314}
315
316
317
318template <typename T, typename P>
319inline ObserverPointer<T, P>::ObserverPointer(T *t, const std::string &id)
320 : pointer(t)
321 , id(id)
322 , pointed_to_object_is_alive(false)
323{
324 static_assert(std::is_base_of_v<Subscriptor, T>,
325 "This class can only be used if the first template argument "
326 "is a class derived from 'Subscriptor'.");
327
328 if (pointer != nullptr)
329 pointer->subscribe(&pointed_to_object_is_alive, id);
330}
331
332
333
334template <typename T, typename P>
335template <class Q>
337 const ObserverPointer<T, Q> &other)
338 : pointer(other.pointer)
339 , id(other.id)
340 , pointed_to_object_is_alive(false)
341{
342 static_assert(std::is_base_of_v<Subscriptor, T>,
343 "This class can only be used if the first template argument "
344 "is a class derived from 'Subscriptor'.");
345
346 if (other != nullptr)
347 {
349 ExcMessage("You can't copy a smart pointer object that "
350 "is pointing to an object that is no longer alive."));
351 pointer->subscribe(&pointed_to_object_is_alive, id);
352 }
353}
354
355
356
357template <typename T, typename P>
359 const ObserverPointer<T, P> &other)
360 : pointer(other.pointer)
361 , id(other.id)
362 , pointed_to_object_is_alive(false)
363{
364 static_assert(std::is_base_of_v<Subscriptor, T>,
365 "This class can only be used if the first template argument "
366 "is a class derived from 'Subscriptor'.");
367
368 if (other != nullptr)
369 {
371 ExcMessage("You can't copy a smart pointer object that "
372 "is pointing to an object that is no longer alive."));
373 pointer->subscribe(&pointed_to_object_is_alive, id);
374 }
375}
376
377
378
379template <typename T, typename P>
381 ObserverPointer<T, P> &&other) noexcept
382 : pointer(other.pointer)
383 , id(other.id)
384 , pointed_to_object_is_alive(false)
385{
386 static_assert(std::is_base_of_v<Subscriptor, T>,
387 "This class can only be used if the first template argument "
388 "is a class derived from 'Subscriptor'.");
389
390 if (other != nullptr)
391 {
392 Assert(other.pointed_to_object_is_alive,
393 ExcMessage("You can't move a smart pointer object that "
394 "is pointing to an object that is no longer alive."));
395
396 try
397 {
398 pointer->subscribe(&pointed_to_object_is_alive, id);
399 }
400 catch (...)
401 {
402 Assert(false,
404 "Calling subscribe() failed with an exception, but we "
405 "are in a function that cannot throw exceptions. "
406 "Aborting the program here."));
407 }
408
409 // Release the rhs object as if we had moved all members away from
410 // it directly:
411 other = nullptr;
412 }
413}
414
415
416
417template <typename T, typename P>
419{
420 static_assert(std::is_base_of_v<Subscriptor, T>,
421 "This class can only be used if the first template argument "
422 "is a class derived from 'Subscriptor'.");
423
424 if (pointed_to_object_is_alive && pointer != nullptr)
425 pointer->unsubscribe(&pointed_to_object_is_alive, id);
426}
427
428
429
430template <typename T, typename P>
431inline void
433{
434 if (pointed_to_object_is_alive && pointer != nullptr)
435 {
436 pointer->unsubscribe(&pointed_to_object_is_alive, id);
437 delete pointer;
438 Assert(pointed_to_object_is_alive == false, ExcInternalError());
439 }
440 pointer = nullptr;
441}
442
443
444
445template <typename T, typename P>
448{
449 // optimize if no real action is requested
450 if (pointer == tt)
451 return *this;
452
453 // Let us unsubscribe from the current object
454 if (pointed_to_object_is_alive && pointer != nullptr)
455 pointer->unsubscribe(&pointed_to_object_is_alive, id);
456
457 // Then reset to the new object, and subscribe to it
458 pointer = tt;
459 if (tt != nullptr)
460 pointer->subscribe(&pointed_to_object_is_alive, id);
461
462 return *this;
463}
464
465
466
467template <typename T, typename P>
468template <class Q>
471{
472 // if objects on the left and right
473 // hand side of the operator= are
474 // the same, then this is a no-op
475 if (&other == this)
476 return *this;
477
478 // Let us unsubscribe from the current object
479 if (pointed_to_object_is_alive && pointer != nullptr)
480 pointer->unsubscribe(&pointed_to_object_is_alive, id);
481
482 // Then reset to the new object, and subscribe to it
483 pointer = (other != nullptr ? other.get() : nullptr);
484 if (other != nullptr)
485 {
487 ExcMessage("You can't copy a smart pointer object that "
488 "is pointing to an object that is no longer alive."));
489 pointer->subscribe(&pointed_to_object_is_alive, id);
490 }
491 return *this;
492}
493
494
495
496template <typename T, typename P>
499{
500 // if objects on the left and right
501 // hand side of the operator= are
502 // the same, then this is a no-op
503 if (&other == this)
504 return *this;
505
506 // Let us unsubscribe from the current object
507 if (pointed_to_object_is_alive && pointer != nullptr)
508 pointer->unsubscribe(&pointed_to_object_is_alive, id);
509
510 // Then reset to the new object, and subscribe to it
511 pointer = (other != nullptr ? other.get() : nullptr);
512 if (other != nullptr)
513 {
515 ExcMessage("You can't copy a smart pointer object that "
516 "is pointing to an object that is no longer alive."));
517 pointer->subscribe(&pointed_to_object_is_alive, id);
518 }
519 return *this;
520}
521
522
523
524template <typename T, typename P>
527{
528 if (other == nullptr)
529 {
530 *this = nullptr;
531 }
532 // if objects on the left and right hand side of the operator= are
533 // the same, then this is a no-op
534 else if (&other != this)
535 {
536 // Let us unsubscribe from the current object
537 if (pointer != nullptr && pointed_to_object_is_alive)
538 pointer->unsubscribe(&pointed_to_object_is_alive, id);
539
540 // Then reset to the new object, and subscribe to it:
541 Assert(other.pointed_to_object_is_alive,
542 ExcMessage("You can't move a smart pointer object that "
543 "is pointing to an object that is no longer alive."));
544 pointer = other.get();
545 try
546 {
547 pointer->subscribe(&pointed_to_object_is_alive, id);
548 }
549 catch (...)
550 {
551 Assert(false,
553 "Calling subscribe() failed with an exception, but we "
554 "are in a function that cannot throw exceptions. "
555 "Aborting the program here."));
556 }
557
558 // Finally release the rhs object since we moved its contents
559 other = nullptr;
560 }
561 return *this;
562}
563
564
565
566template <typename T, typename P>
568{
569 return pointer;
570}
571
572
573
574template <typename T, typename P>
575inline T &
577{
578 Assert(pointer != nullptr, ExcNotInitialized());
579 Assert(pointed_to_object_is_alive,
580 ExcMessage("The object pointed to is not valid anymore."));
581 return *pointer;
582}
583
584
585
586template <typename T, typename P>
587inline T *
589{
590 Assert(pointer != nullptr, ExcNotInitialized());
591 Assert(pointed_to_object_is_alive,
592 ExcMessage("The object pointed to is not valid anymore."));
593 return pointer;
594}
595
596
597
598template <typename T, typename P>
599inline T *
601{
602 return this->get();
603}
604
605
606
607template <typename T, typename P>
608template <class Q>
609inline void
611{
612#ifdef DEBUG
613 ObserverPointer<T, P> aux(pointer, id);
614 *this = other;
615 other = aux;
616#else
617 std::swap(pointer, other.pointer);
618#endif
619}
620
621
622
623template <typename T, typename P>
624inline void
626{
627 if (pointed_to_object_is_alive && pointer != nullptr)
628 pointer->unsubscribe(pointed_to_object_is_alive, id);
629
630 std::swap(pointer, ptr);
631
632 if (pointer != nullptr)
633 pointer->subscribe(pointed_to_object_is_alive, id);
634}
635
636
637
638template <typename T, typename P>
639inline std::size_t
644
645
646
647// The following function is not strictly necessary but is an optimization
648// for places where you call swap(p1,p2) with ObserverPointer objects p1, p2.
649// Unfortunately, MS Visual Studio (at least up to the 2013 edition) trips
650// over it when calling std::swap(v1,v2) where v1,v2 are std::vectors of
651// ObserverPointer objects: it can't determine whether it should call std::swap
652// or ::swap on the individual elements (see bug #184 on our Google Code
653// site. Consequently, just take this function out of the competition for this
654// compiler.
655#ifndef _MSC_VER
661template <typename T, typename P, class Q>
662inline void
664{
665 t1.swap(t2);
666}
667#endif
668
669
677template <typename T, typename P>
678inline void
680{
681 t1.swap(t2);
682}
683
684
685
693template <typename T, typename P>
694inline void
696{
697 t2.swap(t1);
698}
699
701
702#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:207
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:500
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:501
#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)