Reference documentation for deal.II version 9.2.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\}}\)
subscriptor.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2019 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/logstream.h>
18 
19 #include <algorithm>
20 #include <iostream>
21 #include <string>
22 #include <typeinfo>
23 
25 
26 
27 static const char *unknown_subscriber = "unknown subscriber";
28 
29 
30 std::mutex Subscriptor::mutex;
31 
32 
33 Subscriptor::Subscriptor(Subscriptor &&subscriptor) noexcept
34  : counter(0)
35  , object_info(subscriptor.object_info)
36 {
37  for (const auto validity_ptr : subscriptor.validity_pointers)
38  *validity_ptr = false;
39 }
40 
41 
42 
44 {
45  for (const auto validity_ptr : validity_pointers)
46  *validity_ptr = false;
47  object_info = nullptr;
48 }
49 
50 
51 void
53 {
54  // Check whether there are still subscriptions to this object. If so, output
55  // the actual name of the class to which this object belongs, i.e. the most
56  // derived class. Note that the name may be mangled, so it need not be the
57  // clear-text class name. However, you can obtain the latter by running the
58  // c++filt program over the output.
59 #ifdef DEBUG
60 
61  // If there are still active pointers, show a message and kill the program.
62  // However, under some circumstances, this is not so desirable. For example,
63  // in code like this:
64  //
65  // Triangulation tria;
66  // DoFHandler *dh = new DoFHandler(tria);
67  // ...some function that throws an exception
68  //
69  // the exception will lead to the destruction of the triangulation, but since
70  // the dof_handler is on the heap it will not be destroyed. This will trigger
71  // an assertion in the triangulation. If we kill the program at this point, we
72  // will never be able to learn what caused the problem. In this situation,
73  // just display a message and continue the program.
74  if (counter != 0)
75  {
76 # if __cpp_lib_uncaught_exceptions >= 201411
77  // std::uncaught_exception() is deprecated in c++17
78  if (std::uncaught_exceptions() == 0)
79 # else
80  if (std::uncaught_exception() == false)
81 # endif
82  {
83  std::string infostring;
84  for (const auto &map_entry : counter_map)
85  {
86  if (map_entry.second > 0)
87  infostring += std::string("\n from Subscriber ") +
88  std::string(map_entry.first);
89  }
90 
91  if (infostring.empty())
92  infostring = "<none>";
93 
95  ExcInUse(counter.load(),
96  object_info->name(),
97  infostring));
98  }
99  else
100  {
101  std::cerr
102  << "---------------------------------------------------------"
103  << std::endl
104  << "An object pointed to by a SmartPointer is being destroyed."
105  << std::endl
106  << "Under normal circumstances, this would abort the program."
107  << std::endl
108  << "However, another exception is being processed at the"
109  << std::endl
110  << "moment, so the program will continue to run to allow"
111  << std::endl
112  << "this exception to be processed." << std::endl
113  << "---------------------------------------------------------"
114  << std::endl;
115  }
116  }
117 #endif
118 }
119 
120 
121 
122 Subscriptor &
124 {
125  for (const auto validity_ptr : s.validity_pointers)
126  *validity_ptr = false;
127  object_info = s.object_info;
128  return *this;
129 }
130 
131 
132 
133 void
134 Subscriptor::subscribe(std::atomic<bool> *const validity,
135  const std::string & id) const
136 {
137  std::lock_guard<std::mutex> lock(mutex);
138 
139  if (object_info == nullptr)
140  object_info = &typeid(*this);
141  ++counter;
142 
143  const std::string &name = id.empty() ? unknown_subscriber : id;
144 
145  ++counter_map[name];
146 
147  *validity = true;
148  validity_pointers.push_back(validity);
149 }
150 
151 
152 
153 void
154 Subscriptor::unsubscribe(std::atomic<bool> *const validity,
155  const std::string & id) const
156 {
157  const std::string &name = id.empty() ? unknown_subscriber : id;
158 
159  if (counter == 0)
160  {
161  AssertNothrow(counter > 0, ExcNoSubscriber(object_info->name(), name));
162  // This is for the case that we do not abort after the exception
163  return;
164  }
165 
166  std::lock_guard<std::mutex> lock(mutex);
167 
168  map_iterator it = counter_map.find(name);
169  if (it == counter_map.end())
170  {
171  AssertNothrow(it != counter_map.end(),
172  ExcNoSubscriber(object_info->name(), name));
173  // This is for the case that we do not abort after the exception
174  return;
175  }
176  if (it->second == 0)
177  {
178  AssertNothrow(it->second > 0, ExcNoSubscriber(object_info->name(), name));
179  // This is for the case that we do not abort after the exception
180  return;
181  }
182 
183  auto validity_ptr_it =
184  std::find(validity_pointers.begin(), validity_pointers.end(), validity);
185  if (validity_ptr_it == validity_pointers.end())
186  {
188  validity_ptr_it != validity_pointers.end(),
189  ExcMessage(
190  "This Subscriptor object does not know anything about the supplied pointer!"));
191  return;
192  }
193 
194  validity_pointers.erase(validity_ptr_it);
195  --counter;
196  --it->second;
197 }
198 
199 
200 
201 void
203 {
205 }
206 
Subscriptor::ExcInUse
static ::ExceptionBase & ExcInUse(int arg1, std::string arg2, std::string arg3)
Subscriptor::object_info
const std::type_info * object_info
Definition: subscriptor.h:241
Subscriptor::unsubscribe
void unsubscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
Definition: subscriptor.cc:154
Subscriptor::map_iterator
decltype(counter_map)::iterator map_iterator
Definition: subscriptor.h:227
Subscriptor::operator=
Subscriptor & operator=(const Subscriptor &)
Definition: subscriptor.h:283
unknown_subscriber
static const char * unknown_subscriber
Definition: subscriptor.cc:27
Subscriptor::validity_pointers
std::vector< std::atomic< bool > * > validity_pointers
Definition: subscriptor.h:233
Subscriptor::subscribe
void subscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
Definition: subscriptor.cc:134
deallog
LogStream deallog
Definition: logstream.cc:37
Subscriptor
Definition: subscriptor.h:62
Subscriptor::check_no_subscribers
void check_no_subscribers() const noexcept
Definition: subscriptor.cc:52
Subscriptor::list_subscribers
void list_subscribers() const
Definition: subscriptor.cc:202
StandardExceptions::ExcMessage
static ::ExceptionBase & ExcMessage(std::string arg1)
subscriptor.h
DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:358
Subscriptor::counter_map
std::map< std::string, unsigned int > counter_map
Definition: subscriptor.h:217
Subscriptor::ExcNoSubscriber
static ::ExceptionBase & ExcNoSubscriber(std::string arg1, std::string arg2)
AssertNothrow
#define AssertNothrow(cond, exc)
Definition: exceptions.h:1483
DEAL_II_NAMESPACE_CLOSE
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:359
Subscriptor::Subscriptor
Subscriptor()
Definition: subscriptor.h:268
logstream.h
Subscriptor::counter
std::atomic< unsigned int > counter
Definition: subscriptor.h:211
Subscriptor::mutex
static std::mutex mutex
Definition: subscriptor.h:263
Subscriptor::~Subscriptor
virtual ~Subscriptor()
Definition: subscriptor.cc:43