deal.II version GIT relicensing-6842-g793a97d2aa 2026-10-02 14:00:01+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
enable_observer_pointer.cc
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 - 2026 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#include <deal.II/base/config.h>
14
19
20#include <algorithm>
21#include <atomic>
22#include <exception>
23#include <iostream>
24#include <map>
25#include <mutex>
26#include <string>
27#include <typeinfo>
28#include <utility>
29#include <vector>
30
32
33
35
36
38 EnableObserverPointer &&subscriptor) noexcept
39 : counter(0)
40 , object_info(subscriptor.object_info)
41{
42 for (auto *const validity_ptr : subscriptor.validity_pointers)
43 *validity_ptr = false;
44 subscriptor.validity_pointers.clear();
45}
46
47
48
50{
51 for (auto *const validity_ptr : validity_pointers)
52 *validity_ptr = false;
53 object_info = nullptr;
54}
55
56
57void
59{
60 // Check whether there are still subscriptions to this object. If so, output
61 // the actual name of the class to which this object belongs, i.e. the most
62 // derived class. Note that the name may be mangled, so it need not be the
63 // clear-text class name. However, you can obtain the latter by running the
64 // c++filt program over the output.
65 if constexpr (running_in_debug_mode())
66 {
67 // If there are still active pointers, show a message and kill the
68 // program. However, under some circumstances, this is not so desirable.
69 // For example, in code like this:
70 //
71 // Triangulation tria;
72 // DoFHandler *dh = new DoFHandler(tria);
73 // ...some function that throws an exception
74 //
75 // the exception will lead to the destruction of the triangulation, but
76 // since the dof_handler is on the heap it will not be destroyed. This
77 // will trigger an assertion in the triangulation. If we kill the program
78 // at this point, we will never be able to learn what caused the problem.
79 // In this situation, just display a message and continue the program.
80 if (counter != 0)
81 {
82 if (std::uncaught_exceptions() == 0)
83 {
84 std::string infostring;
85 for (const auto &map_entry : counter_map)
86 {
87 if (map_entry.second > 0)
88 infostring +=
89 "\n from Subscriber " + std::string(map_entry.first);
90 }
91
92 if (infostring.empty())
93 infostring = "<none>";
94
96 ExcInUse(counter.load(),
97 object_info->name(),
98 infostring));
99 }
100 else
101 {
102 std::cerr
103 << "---------------------------------------------------------"
104 << std::endl
105 << "An object pointed to by a ObserverPointer is being destroyed."
106 << std::endl
107 << "Under normal circumstances, this would abort the program."
108 << std::endl
109 << "However, another exception is being processed at the"
110 << std::endl
111 << "moment, so the program will continue to run to allow"
112 << std::endl
113 << "this exception to be processed." << std::endl
114 << "---------------------------------------------------------"
115 << std::endl;
116 }
117 }
118 }
119}
120
121
122
125{
126 for (auto *const validity_ptr : s.validity_pointers)
127 *validity_ptr = false;
128 s.validity_pointers.clear();
129 object_info = s.object_info;
130 return *this;
131}
132
133
134
135void
136EnableObserverPointer::subscribe(std::atomic<bool> *const validity,
137 const std::string &id) const
138{
139 std::scoped_lock lock(mutex);
140
141 if (object_info == nullptr)
142 object_info = &typeid(*this);
143 ++counter;
144
145 ++counter_map[id];
146
147 *validity = true;
148 validity_pointers.push_back(validity);
149}
150
151
152
153void
154EnableObserverPointer::unsubscribe(std::atomic<bool> *const validity,
155 const std::string &id) const
156{
157 if (counter == 0)
158 {
160 // This is for the case that we do not abort after the exception
161 return;
162 }
163
164 std::scoped_lock lock(mutex);
165
166 auto it = counter_map.find(id);
167 if (it == counter_map.end())
168 {
169 AssertNothrow(it != counter_map.end(),
170 ExcNoSubscriber(object_info->name(), id));
171 // This is for the case that we do not abort after the exception
172 return;
173 }
174 if (it->second == 0)
175 {
176 AssertNothrow(it->second > 0, ExcNoSubscriber(object_info->name(), id));
177 // This is for the case that we do not abort after the exception
178 return;
179 }
180
181 auto validity_ptr_it =
182 std::find(validity_pointers.begin(), validity_pointers.end(), validity);
183 if (validity_ptr_it == validity_pointers.end())
184 {
186 validity_ptr_it != validity_pointers.end(),
188 "This EnableObserverPointer object does not know anything about the supplied pointer!"));
189 return;
190 }
191
192 validity_pointers.erase(validity_ptr_it);
193 --counter;
194 --it->second;
195}
196
197
198
199void
204
void check_no_subscribers() const noexcept
void subscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
EnableObserverPointer & operator=(const EnableObserverPointer &)
std::atomic< unsigned int > counter
void unsubscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
std::map< std::string, unsigned int > counter_map
std::vector< std::atomic< bool > * > validity_pointers
const std::type_info * object_info
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define AssertNothrow(cond, exc)
static ::ExceptionBase & ExcNoSubscriber(std::string arg1, std::string arg2)
static ::ExceptionBase & ExcInUse(int arg1, std::string arg2, std::string arg3)
static ::ExceptionBase & ExcMessage(std::string arg1)
LogStream deallog
Definition logstream.cc:36