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