From: Daniel Arndt Date: Sat, 6 Oct 2018 00:29:37 +0000 (-0600) Subject: Make SmartPointer+Subscriptor check for dangling pointers X-Git-Tag: v9.1.0-rc1~581^2~1 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9c6a1560024a0220254a2c0effb0fd151c199ea0;p=dealii.git Make SmartPointer+Subscriptor check for dangling pointers --- diff --git a/include/deal.II/base/smartpointer.h b/include/deal.II/base/smartpointer.h index 52f245ad64..8dc4065ebb 100644 --- a/include/deal.II/base/smartpointer.h +++ b/include/deal.II/base/smartpointer.h @@ -24,10 +24,11 @@ DEAL_II_NAMESPACE_OPEN /** - * Smart pointers avoid destruction of an object in use. They can be used just + * Smart pointers avoid using dangling pointers. They can be used just * like a pointer (i.e. using the * and -> operators and - * through casting) but make sure that the object pointed to is not deleted in - * the course of use of the pointer by signaling the pointee its use. + * through casting) but make sure that the object pointed to is not deleted or + * moved from in the course of use of the pointer by signaling the pointee its + * use. * * Objects pointed to, i.e. the class T, should inherit Subscriptor or must * implement the same functionality. Null pointers are an exception from this @@ -84,7 +85,7 @@ public: SmartPointer(const SmartPointer &tt); /** - * Constructor taking a normal pointer. If possible, i.e. if the pointer is + * Constructor taking a normal pointer. If possible, i.e. if the pointer is * not a null pointer, the constructor subscribes to the given object to * lock it, i.e. to prevent its destruction before the end of its use. * @@ -94,14 +95,13 @@ public: SmartPointer(T *t, const char *id); /** - * Constructor taking a normal pointer. If possible, i.e. if the pointer is + * Constructor taking a normal pointer. If possible, i.e. if the pointer is * not a null pointer, the constructor subscribes to the given object to * lock it, i.e. to prevent its destruction before the end of its use. The * id of this pointer is set to the name of the class P. */ SmartPointer(T *t); - /** * Destructor, removing the subscription. */ @@ -117,7 +117,7 @@ public: operator=(T *tt); /** - * Assignment operator for SmartPointer. The pointer subscribes to the new + * Assignment operator for SmartPointer. The pointer subscribes to the new * object automatically and unsubscribes to an old one if it exists. */ template @@ -125,7 +125,7 @@ public: operator=(const SmartPointer &tt); /** - * Assignment operator for SmartPointer. The pointer subscribes to the new + * Assignment operator for SmartPointer. The pointer subscribes to the new * object automatically and unsubscribes to an old one if it exists. */ SmartPointer & @@ -143,13 +143,13 @@ public: operator T *() const; /** - * Dereferencing operator. This operator throws an ExcNotInitialized if the + * Dereferencing operator. This operator throws an ExcNotInitialized() if the * pointer is a null pointer. */ T &operator*() const; /** - * Dereferencing operator. This operator throws an ExcNotInitialized if the + * Dereferencing operator. This operator throws an ExcNotInitializedi() if the * pointer is a null pointer. */ T *operator->() const; @@ -198,6 +198,12 @@ private: * The identification for the subscriptor. */ const char *const id; + + /** + * The Smartpointer is invalidated when the object pointed to is destroyed + * or moved from. + */ + bool pointed_to_object_is_alive; }; @@ -208,6 +214,7 @@ template inline SmartPointer::SmartPointer() : t(nullptr) , id(typeid(P).name()) + , pointed_to_object_is_alive(false) {} @@ -216,9 +223,10 @@ template inline SmartPointer::SmartPointer(T *t) : t(t) , id(typeid(P).name()) + , pointed_to_object_is_alive(false) { if (t != nullptr) - t->subscribe(id); + t->subscribe(&pointed_to_object_is_alive, id); } @@ -227,9 +235,10 @@ template inline SmartPointer::SmartPointer(T *t, const char *id) : t(t) , id(id) + , pointed_to_object_is_alive(false) { if (t != nullptr) - t->subscribe(id); + t->subscribe(&pointed_to_object_is_alive, id); } @@ -239,9 +248,10 @@ template inline SmartPointer::SmartPointer(const SmartPointer &tt) : t(tt.t) , id(tt.id) + , pointed_to_object_is_alive(false) { - if (t != nullptr) - t->subscribe(id); + if (tt.pointed_to_object_is_alive && t != nullptr) + t->subscribe(&pointed_to_object_is_alive, id); } @@ -250,9 +260,10 @@ template inline SmartPointer::SmartPointer(const SmartPointer &tt) : t(tt.t) , id(tt.id) + , pointed_to_object_is_alive(false) { - if (t != nullptr) - t->subscribe(id); + if (tt.pointed_to_object_is_alive && t != nullptr) + t->subscribe(&pointed_to_object_is_alive, id); } @@ -260,8 +271,8 @@ inline SmartPointer::SmartPointer(const SmartPointer &tt) template inline SmartPointer::~SmartPointer() { - if (t != nullptr) - t->unsubscribe(id); + if (pointed_to_object_is_alive && t != nullptr) + t->unsubscribe(&pointed_to_object_is_alive, id); } @@ -270,12 +281,13 @@ template inline void SmartPointer::clear() { - if (t != nullptr) + if (pointed_to_object_is_alive && t != nullptr) { - t->unsubscribe(id); + t->unsubscribe(&pointed_to_object_is_alive, id); delete t; - t = nullptr; + Assert(pointed_to_object_is_alive == false, ExcInternalError()); } + t = nullptr; } @@ -289,11 +301,11 @@ SmartPointer::operator=(T *tt) if (t == tt) return *this; - if (t != nullptr) - t->unsubscribe(id); + if (pointed_to_object_is_alive && t != nullptr) + t->unsubscribe(&pointed_to_object_is_alive, id); t = tt; if (tt != nullptr) - tt->subscribe(id); + tt->subscribe(&pointed_to_object_is_alive, id); return *this; } @@ -310,11 +322,11 @@ SmartPointer::operator=(const SmartPointer &tt) if (&tt == this) return *this; - if (t != nullptr) - t->unsubscribe(id); + if (pointed_to_object_is_alive && t != nullptr) + t->unsubscribe(&pointed_to_object_is_alive, id); t = static_cast(tt); - if (tt != nullptr) - tt->subscribe(id); + if (tt.pointed_to_object_is_alive && tt != nullptr) + tt->subscribe(&pointed_to_object_is_alive, id); return *this; } @@ -330,11 +342,11 @@ SmartPointer::operator=(const SmartPointer &tt) if (&tt == this) return *this; - if (t != nullptr) - t->unsubscribe(id); + if (pointed_to_object_is_alive && t != nullptr) + t->unsubscribe(&pointed_to_object_is_alive, id); t = static_cast(tt); - if (tt != nullptr) - tt->subscribe(id); + if (tt.pointed_to_object_is_alive && tt != nullptr) + tt->subscribe(&pointed_to_object_is_alive, id); return *this; } @@ -352,6 +364,8 @@ template inline T &SmartPointer::operator*() const { Assert(t != nullptr, ExcNotInitialized()); + Assert(pointed_to_object_is_alive, + ExcMessage("The object pointed to is not valid anymore.")); return *t; } @@ -361,6 +375,8 @@ template inline T *SmartPointer::operator->() const { Assert(t != nullptr, ExcNotInitialized()); + Assert(pointed_to_object_is_alive, + ExcMessage("The object pointed to is not valid anymore.")); return t; } @@ -386,13 +402,13 @@ template inline void SmartPointer::swap(T *&tt) { - if (t != nullptr) - t->unsubscribe(id); + if (pointed_to_object_is_alive && t != nullptr) + t->unsubscribe(pointed_to_object_is_alive, id); std::swap(t, tt); if (t != nullptr) - t->subscribe(id); + t->subscribe(pointed_to_object_is_alive, id); } diff --git a/include/deal.II/base/subscriptor.h b/include/deal.II/base/subscriptor.h index d1dbc9d074..5648ac9afc 100644 --- a/include/deal.II/base/subscriptor.h +++ b/include/deal.II/base/subscriptor.h @@ -26,6 +26,7 @@ #include #include #include +#include DEAL_II_NAMESPACE_OPEN @@ -33,28 +34,29 @@ DEAL_II_NAMESPACE_OPEN * Handling of subscriptions. * * This class, as a base class, allows to keep track of other objects using a - * specific object. It is used, when an object, given to a constructor by - * reference, is stored. Then, the original object may not be deleted before - * the dependent object is deleted. You can assert this constraint by letting - * the object passed be derived from this class and let the user subscribe() - * to this object. The destructor the used object inherits from the - * Subscriptor class then will lead to an error when destruction is attempted - * while there are still subscriptions. + * specific object. It is used to avoid that pointers that point to an object of + * a class derived from Subscriptor are referenced after that object has been + * invalidated. Here, invalidation is assumend to happen when the object is + * moved from or destroyed. + * The mechanism works as follows: The member function subscribe() accepts a + * pointer to a boolean that is modified on invalidation. The object that owns + * this pointer (usually an object of class type SmartPointer) is then expected + * to check the state of the boolean before trying to access this class. * * The utility of this class is even enhanced by providing identifying strings - * to the functions subscribe() and unsubscribe(). In case of a hanging - * subscription during destruction, this string will be listed in the - * exception's message. These strings are represented as const char - * * pointers since the underlying buffer comes from (and is managed - * by) the run-time type information system: more exactly, these pointers are - * the result the function call typeid(x).name() where + * to the functions subscribe() and unsubscribe(). These strings are represented + * as const char pointers since the underlying buffer comes from + * (and is managed by) the run-time type information system: more exactly, these + * pointers are the result the function call typeid(x).name() where * x is some object. Therefore, the pointers provided to * subscribe() and to unsubscribe() must be the same. Strings with equal * contents will not be recognized to be the same. The handling in * SmartPointer will take care of this. + * The current subscribers to this class can be obtained by calling + * list_subscribers(). * * @ingroup memory - * @author Guido Kanschat, 1998 - 2005 + * @author Guido Kanschat, Daniel Arndt, 1998 - 2005, 2018 */ class Subscriptor { @@ -95,28 +97,26 @@ public: operator=(const Subscriptor &); /** - * Move assignment operator. - * - * Asserts that the counter for the moved object is zero. + * Move assignment operator. Only invalidates the object moved from. */ Subscriptor & operator=(Subscriptor &&) noexcept; /** - * Subscribes a user of the object. The subscriber may be identified by text - * supplied as identifier. + * Subscribes a user of the object by storing the pointer @p validity. The + * subscriber may be identified by text supplied as @p identifier. */ void - subscribe(const char *identifier = nullptr) const; + subscribe(bool *const validity, const char *identifier = nullptr) const; /** * Unsubscribes a user from the object. * - * @note The identifier must be the same pointer as the one - * supplied to subscribe(), not just the same text. + * @note The @p identifier and the @p validity pointer must be the same as + * the one supplied to subscribe(). */ void - unsubscribe(const char *identifier = nullptr) const; + unsubscribe(bool *const validity, const char *identifier = nullptr) const; /** * Return the present number of subscriptions to this object. This allows to @@ -223,6 +223,12 @@ private: */ mutable std::map counter_map; + /** + * In this vector, we store pointers to the validity bool in the SmartPointer + * objects that subscribe to this class. + */ + mutable std::vector validity_pointers; + /** * Pointer to the typeinfo object of this object, from which we can later * deduce the class name. Since this information on the derived class is diff --git a/source/base/subscriptor.cc b/source/base/subscriptor.cc index 5cef19f1b0..eed36ac147 100644 --- a/source/base/subscriptor.cc +++ b/source/base/subscriptor.cc @@ -51,14 +51,16 @@ Subscriptor::Subscriptor(Subscriptor &&subscriptor) noexcept : counter(0) , object_info(subscriptor.object_info) { - subscriptor.check_no_subscribers(); + for (auto validity_ptr : subscriptor.validity_pointers) + *validity_ptr = false; } Subscriptor::~Subscriptor() { - check_no_subscribers(); + for (auto validity_ptr : validity_pointers) + *validity_ptr = false; object_info = nullptr; } @@ -133,7 +135,6 @@ Subscriptor::check_no_subscribers() const noexcept Subscriptor & Subscriptor::operator=(const Subscriptor &s) { - check_no_subscribers(); object_info = s.object_info; return *this; } @@ -143,8 +144,8 @@ Subscriptor::operator=(const Subscriptor &s) Subscriptor & Subscriptor::operator=(Subscriptor &&s) noexcept { - check_no_subscribers(); - s.check_no_subscribers(); + for (auto validity_ptr : s.validity_pointers) + *validity_ptr = false; object_info = s.object_info; return *this; } @@ -152,7 +153,7 @@ Subscriptor::operator=(Subscriptor &&s) noexcept void -Subscriptor::subscribe(const char *id) const +Subscriptor::subscribe(bool *const validity, const char *id) const { std::lock_guard lock(mutex); @@ -165,14 +166,16 @@ Subscriptor::subscribe(const char *id) const map_iterator it = counter_map.find(name); if (it == counter_map.end()) counter_map.insert(map_value_type(name, 1U)); - else it->second++; + + *validity = true; + validity_pointers.push_back(validity); } void -Subscriptor::unsubscribe(const char *id) const +Subscriptor::unsubscribe(bool *const validity, const char *id) const { const char *name = (id != nullptr) ? id : unknown_subscriber; AssertNothrow(counter > 0, ExcNoSubscriber(object_info->name(), name)); @@ -195,6 +198,18 @@ Subscriptor::unsubscribe(const char *id) const --counter; it->second--; } + + auto validity_ptr_it = + std::find(validity_pointers.begin(), validity_pointers.end(), validity); + if (validity_ptr_it == validity_pointers.end()) + { + AssertNothrow( + validity_ptr_it != validity_pointers.end(), + ExcMessage( + "This Subscriptor object does not know anything about the supplied pointer!")); + } + else + validity_pointers.erase(validity_ptr_it); } diff --git a/tests/base/assign_subscriptor.cc b/tests/base/assign_subscriptor.cc index 0c738201a4..c38e3be2b7 100644 --- a/tests/base/assign_subscriptor.cc +++ b/tests/base/assign_subscriptor.cc @@ -15,7 +15,8 @@ -// check that Subscriptor objects need to be empty before assigning. +// Check the behavior of the SmartPointer-Subscriptor pair +// for copy and move semantics. #include @@ -36,55 +37,112 @@ main() initlog(); - // should work { - Subscriptor subscriptor_1; - Subscriptor subscriptor_2; + deallog << "Checking copy assignment" << std::endl; - SmartPointer smart(&subscriptor_1); + Subscriptor subscriptor_1; + Subscriptor subscriptor_2; + SmartPointer smart_pointer_1(&subscriptor_1); + SmartPointer smart_pointer_2(&subscriptor_2); subscriptor_2 = subscriptor_1; + + deallog << "Checking smart_pointer_1" << std::endl; + try + { + const auto dummy_1 = *smart_pointer_1; + (void)dummy_1; + } + catch (ExceptionBase &e) + { + deallog << e.get_exc_name() << std::endl; + } + + deallog << "Checking smart_pointer_2" << std::endl; + try + { + const auto dummy_2 = *smart_pointer_2; + (void)dummy_2; + } + catch (ExceptionBase &e) + { + deallog << e.get_exc_name() << std::endl; + } + deallog << std::endl; } - try - { - Subscriptor subscriptor_1; - Subscriptor subscriptor_2; - - SmartPointer smart(&subscriptor_2); - - subscriptor_2 = subscriptor_1; - } - catch (ExceptionBase &e) - { - deallog << e.get_exc_name() << std::endl; - } - - try - { - Subscriptor subscriptor_1; - Subscriptor subscriptor_2; - - SmartPointer smart(&subscriptor_1); - - subscriptor_2 = std::move(subscriptor_1); - } - catch (ExceptionBase &e) - { - deallog << e.get_exc_name() << std::endl; - } - - try - { - Subscriptor subscriptor_1; - Subscriptor subscriptor_2; - - SmartPointer smart(&subscriptor_2); - - subscriptor_2 = std::move(subscriptor_1); - } - catch (ExceptionBase &e) - { - deallog << e.get_exc_name() << std::endl; - } + { + deallog << "Checking copy construction" << std::endl; + + Subscriptor subscriptor_1; + SmartPointer smart_pointer_1(&subscriptor_1); + + Subscriptor subscriptor_2(subscriptor_1); + + deallog << "Checking smart_pointer_1" << std::endl; + try + { + const auto dummy_1 = *smart_pointer_1; + (void)dummy_1; + } + catch (ExceptionBase &e) + { + deallog << e.get_exc_name() << std::endl; + } + deallog << std::endl; + } + + { + deallog << "Checking move assignement" << std::endl; + + Subscriptor subscriptor_1; + Subscriptor subscriptor_2; + SmartPointer smart_pointer_1(&subscriptor_1); + SmartPointer smart_pointer_2(&subscriptor_2); + + subscriptor_2 = std::move(subscriptor_1); + + deallog << "Checking smart_pointer_1" << std::endl; + try + { + const auto dummy_1 = *smart_pointer_1; + (void)dummy_1; + } + catch (ExceptionBase &e) + { + deallog << e.get_exc_name() << std::endl; + } + + deallog << "Checking smart_pointer_2" << std::endl; + try + { + const auto dummy_2 = *smart_pointer_2; + (void)dummy_2; + } + catch (ExceptionBase &e) + { + deallog << e.get_exc_name() << std::endl; + } + deallog << std::endl; + } + + { + deallog << "Checking move construction" << std::endl; + + Subscriptor subscriptor_1; + SmartPointer smart_pointer_1(&subscriptor_1); + + Subscriptor subscriptor_2(std::move(subscriptor_1)); + + deallog << "Checking smart_pointer_1" << std::endl; + try + { + const auto dummy_1 = *smart_pointer_1; + (void)dummy_1; + } + catch (ExceptionBase &e) + { + deallog << e.get_exc_name() << std::endl; + } + } } diff --git a/tests/base/assign_subscriptor.debug.output b/tests/base/assign_subscriptor.debug.output index a5af59129d..4d3bb27e55 100644 --- a/tests/base/assign_subscriptor.debug.output +++ b/tests/base/assign_subscriptor.debug.output @@ -1,49 +1,16 @@ -DEAL::Exception: ExcInUse (counter.load(), object_info->name(), infostring) +DEAL::Checking copy assignment +DEAL::Checking smart_pointer_1 +DEAL::Checking smart_pointer_2 DEAL:: --------------------------------------------------------- -An error occurred in file in function - void dealii::Subscriptor::check_no_subscribers() const -The violated condition was: - counter == 0 -Additional information: - Object of class N6dealii11SubscriptorE is still used by 1 other objects. - -(Additional information: - from Subscriber v) - -See the entry in the Frequently Asked Questions of deal.II (linked to from http://www.dealii.org/) for a lot more information on what this error means and how to fix programs in which it happens. --------------------------------------------------------- - -DEAL::Exception: ExcInUse (counter.load(), object_info->name(), infostring) +DEAL::Checking copy construction +DEAL::Checking smart_pointer_1 DEAL:: --------------------------------------------------------- -An error occurred in file in function - void dealii::Subscriptor::check_no_subscribers() const -The violated condition was: - counter == 0 -Additional information: - Object of class N6dealii11SubscriptorE is still used by 1 other objects. - -(Additional information: - from Subscriber v) - -See the entry in the Frequently Asked Questions of deal.II (linked to from http://www.dealii.org/) for a lot more information on what this error means and how to fix programs in which it happens. --------------------------------------------------------- - -DEAL::Exception: ExcInUse (counter.load(), object_info->name(), infostring) +DEAL::Checking move assignement +DEAL::Checking smart_pointer_1 +DEAL::ExcMessage("The object pointed to is not valid anymore.") +DEAL::Checking smart_pointer_2 DEAL:: --------------------------------------------------------- -An error occurred in file in function - void dealii::Subscriptor::check_no_subscribers() const -The violated condition was: - counter == 0 -Additional information: - Object of class N6dealii11SubscriptorE is still used by 1 other objects. - -(Additional information: - from Subscriber v) - -See the entry in the Frequently Asked Questions of deal.II (linked to from http://www.dealii.org/) for a lot more information on what this error means and how to fix programs in which it happens. --------------------------------------------------------- - +DEAL::Checking move construction +DEAL::Checking smart_pointer_1 +DEAL::ExcMessage("The object pointed to is not valid anymore.") diff --git a/tests/base/reference.cc b/tests/base/reference.cc index 73a43d409f..f9951515c9 100644 --- a/tests/base/reference.cc +++ b/tests/base/reference.cc @@ -60,28 +60,6 @@ public: }; -// A sentinel that stores a reference to a SmartPointer and resets the -// Smartpointer in its destructor. - -template -class Sentinel -{ -public: - Sentinel(SmartPointer &smart_pointer) - : smart_pointer_(smart_pointer) - {} - - ~Sentinel() - { - // This assumes that the first object stored in SmartPointer is a raw - // pointer T* - *reinterpret_cast(&smart_pointer_) = nullptr; - } - -private: - SmartPointer &smart_pointer_; -}; - int main() @@ -118,20 +96,17 @@ main() Test c("C"); r = &c; - // We have to dance a happy little dance here: - // - // In our case the object D defined below will go out of scope before the - // smartpointer "Test R" does. Under normal circumstances this triggers - // an ExcNotUsed and aborts the program. BUT, this is a unit test and so, - // aborting on exception is disabled and we continue execution. - // Unfortunately, this triggers a "use after scope" memory access error - // when finally "Test R" goes out of scope and tries to unsubscribe from - // D that already got destroyed. - // - // Work around this issue by creating a sentinel that gets destroyed - // after D but before "Test R" that simply resets the SmartPointer. - Sentinel sentinel(r); - - Test d("D"); - r = &d; + // Test that a dangling pointer is correctly detected. + try + { + { + Test d("D"); + r = &d; + } + const auto dummy = *r; + } + catch (const ExceptionBase &exc) + { + deallog << exc.get_exc_name() << std::endl; + } } diff --git a/tests/base/reference.debug.output b/tests/base/reference.debug.output index 57dee6addc..2c5020edca 100644 --- a/tests/base/reference.debug.output +++ b/tests/base/reference.debug.output @@ -10,22 +10,7 @@ DEAL::u const DEAL::Construct C DEAL::Construct D DEAL::Destruct D -DEAL::Exception: ExcInUse (counter.load(), object_info->name(), infostring) -DEAL:: --------------------------------------------------------- -An error occurred in file in function - void dealii::Subscriptor::check_no_subscribers() const -The violated condition was: - counter == 0 -Additional information: - Object of class 4Test is still used by 1 other objects. - -(Additional information: - from Subscriber Test R) - -See the entry in the Frequently Asked Questions of deal.II (linked to from http://www.dealii.org/) for a lot more information on what this error means and how to fix programs in which it happens. --------------------------------------------------------- - +DEAL::ExcMessage("The object pointed to is not valid anymore.") DEAL::Destruct C DEAL::Destruct B DEAL::Destruct A diff --git a/tests/base/unsubscribe_subscriptor.cc b/tests/base/unsubscribe_subscriptor.cc index 84bc7487b1..ec51969fb0 100644 --- a/tests/base/unsubscribe_subscriptor.cc +++ b/tests/base/unsubscribe_subscriptor.cc @@ -37,9 +37,10 @@ main() initlog(); Subscriptor subscriptor; - subscriptor.subscribe("a"); - subscriptor.unsubscribe("b"); - subscriptor.unsubscribe("a"); + bool dummy_a; + subscriptor.subscribe(&dummy_a, "a"); + subscriptor.unsubscribe(&dummy_a, "b"); + subscriptor.unsubscribe(&dummy_a, "a"); return 0; } diff --git a/tests/base/unsubscribe_subscriptor.debug.output b/tests/base/unsubscribe_subscriptor.debug.output index c2fb9adbc9..f9eabb1aa7 100644 --- a/tests/base/unsubscribe_subscriptor.debug.output +++ b/tests/base/unsubscribe_subscriptor.debug.output @@ -3,10 +3,21 @@ DEAL::Exception: ExcNoSubscriber(object_info->name(), name) DEAL:: -------------------------------------------------------- An error occurred in file in function - void dealii::Subscriptor::unsubscribe(const char*) const + void dealii::Subscriptor::unsubscribe(bool*, const char*) const The violated condition was: it != counter_map.end() Additional information: No subscriber with identifier subscribes to this object of class N6dealii11SubscriptorE. Consequently, it cannot be unsubscribed. -------------------------------------------------------- +DEAL::Exception: ExcMessage( "This Subscriptor object does not know anything about the supplied pointer!") +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + void dealii::Subscriptor::unsubscribe(bool*, const char*) const +The violated condition was: + validity_ptr_it != validity_pointers.end() +Additional information: + This Subscriptor object does not know anything about the supplied pointer! +-------------------------------------------------------- +