]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Make SmartPointer+Subscriptor check for dangling pointers
authorDaniel Arndt <daniel.arndt@iwr.uni-heidelberg.de>
Sat, 6 Oct 2018 00:29:37 +0000 (18:29 -0600)
committerDaniel Arndt <daniel.arndt@iwr.uni-heidelberg.de>
Fri, 2 Nov 2018 12:41:32 +0000 (13:41 +0100)
include/deal.II/base/smartpointer.h
include/deal.II/base/subscriptor.h
source/base/subscriptor.cc
tests/base/assign_subscriptor.cc
tests/base/assign_subscriptor.debug.output
tests/base/reference.cc
tests/base/reference.debug.output
tests/base/unsubscribe_subscriptor.cc
tests/base/unsubscribe_subscriptor.debug.output

index 52f245ad6428a3ba79f0a91b3abd90d8b1a93ad9..8dc4065ebbfdfc2e8a98728b0ef15caebf6dcdf5 100644 (file)
 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 <tt>*</tt> and <tt>-></tt> 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<T, P> &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 <class Q>
@@ -125,7 +125,7 @@ public:
   operator=(const SmartPointer<T, Q> &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<T, P> &
@@ -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 <typename T, typename P>
 inline SmartPointer<T, P>::SmartPointer()
   : t(nullptr)
   , id(typeid(P).name())
+  , pointed_to_object_is_alive(false)
 {}
 
 
@@ -216,9 +223,10 @@ template <typename T, typename P>
 inline SmartPointer<T, P>::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 <typename T, typename P>
 inline SmartPointer<T, P>::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 <class Q>
 inline SmartPointer<T, P>::SmartPointer(const SmartPointer<T, Q> &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 <typename T, typename P>
 inline SmartPointer<T, P>::SmartPointer(const SmartPointer<T, P> &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<T, P>::SmartPointer(const SmartPointer<T, P> &tt)
 template <typename T, typename P>
 inline SmartPointer<T, P>::~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 <typename T, typename P>
 inline void
 SmartPointer<T, P>::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<T, P>::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<T, P>::operator=(const SmartPointer<T, Q> &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<T *>(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<T, P>::operator=(const SmartPointer<T, P> &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<T *>(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 <typename T, typename P>
 inline T &SmartPointer<T, P>::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 <typename T, typename P>
 inline T *SmartPointer<T, P>::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 <typename T, typename P>
 inline void
 SmartPointer<T, P>::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);
 }
 
 
index d1dbc9d074f303eadb0a4bd7bcaf1b6a2eedf19a..5648ac9afcf0d5bdb2a376d6f472e178dad24ff5 100644 (file)
@@ -26,6 +26,7 @@
 #include <mutex>
 #include <string>
 #include <typeinfo>
+#include <vector>
 
 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 <code>const char
- * *</code> 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 <code>typeid(x).name()</code> where
+ * to the functions subscribe() and unsubscribe(). These strings are represented
+ * as <code>const char</code> 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 <code>typeid(x).name()</code> where
  * <code>x</code> 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 <tt>identifier</tt>.
+   * 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 <tt>identifier</tt> must be the <b>same pointer</b> 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<const char *, unsigned int> counter_map;
 
+  /**
+   * In this vector, we store pointers to the validity bool in the SmartPointer
+   * objects that subscribe to this class.
+   */
+  mutable std::vector<bool *> 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
index 5cef19f1b0c2165249061a0197215f45bf1a7120..eed36ac147fb2291c4d0e5aa70321caebed0708a 100644 (file)
@@ -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<std::mutex> 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);
 }
 
 
index 0c738201a4265033f92c7298bec530dcd9c1cfe8..c38e3be2b7320ff097e1b4bd8957cd9f5c93fdaf 100644 (file)
@@ -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 <deal.II/base/smartpointer.h>
@@ -36,55 +37,112 @@ main()
 
   initlog();
 
-  // should work
   {
-    Subscriptor subscriptor_1;
-    Subscriptor subscriptor_2;
+    deallog << "Checking copy assignment" << std::endl;
 
-    SmartPointer<Subscriptor> smart(&subscriptor_1);
+    Subscriptor               subscriptor_1;
+    Subscriptor               subscriptor_2;
+    SmartPointer<Subscriptor> smart_pointer_1(&subscriptor_1);
+    SmartPointer<Subscriptor> 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<Subscriptor> 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<Subscriptor> 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<Subscriptor> 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<Subscriptor> 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<Subscriptor> smart_pointer_1(&subscriptor_1);
+    SmartPointer<Subscriptor> 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<Subscriptor> 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;
+      }
+  }
 }
index a5af59129df9722a1591fd9638cf33d0011b4f7a..4d3bb27e557c22ba359016cdb78adb1713aaa579 100644 (file)
@@ -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 <subscriptor.cc> 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 <subscriptor.cc> 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 <subscriptor.cc> 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.")
index 73a43d409fe4989e5ddfa4f15f3042242742e7e8..f9951515c9deaf7ddc34acd8b7dc1a6ce0e524f4 100644 (file)
@@ -60,28 +60,6 @@ public:
 };
 
 
-// A sentinel that stores a reference to a SmartPointer and resets the
-// Smartpointer in its destructor.
-
-template <typename T, typename P>
-class Sentinel
-{
-public:
-  Sentinel(SmartPointer<T, P> &smart_pointer)
-    : smart_pointer_(smart_pointer)
-  {}
-
-  ~Sentinel()
-  {
-    // This assumes that the first object stored in SmartPointer is a raw
-    // pointer T*
-    *reinterpret_cast<T **>(&smart_pointer_) = nullptr;
-  }
-
-private:
-  SmartPointer<T, P> &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<Test, Test> 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;
+    }
 }
index 57dee6addc01dc4598ddbc3f438b99a2a0cf3780..2c5020edca0cf2017fcb84ec2bcfd754d159421e 100644 (file)
@@ -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 <subscriptor.cc> 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
index 84bc7487b13ee6c11994627e4c302fdbee593388..ec51969fb02f67137020defc5dd145998b2abe2a 100644 (file)
@@ -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;
 }
index c2fb9adbc9d05ddd904b7797f3638514fc250688..f9eabb1aa75e1adae7a452a5dc2e7b49a4b51e08 100644 (file)
@@ -3,10 +3,21 @@ DEAL::Exception: ExcNoSubscriber(object_info->name(), name)
 DEAL::
 --------------------------------------------------------
 An error occurred in file <subscriptor.cc> 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 <b> 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 <subscriptor.cc> 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!
+--------------------------------------------------------
+

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.