]> https://gitweb.dealii.org/ - dealii.git/commitdiff
New identification strings
authorGuido Kanschat <dr.guido.kanschat@gmail.com>
Wed, 16 Mar 2005 03:20:56 +0000 (03:20 +0000)
committerGuido Kanschat <dr.guido.kanschat@gmail.com>
Wed, 16 Mar 2005 03:20:56 +0000 (03:20 +0000)
git-svn-id: https://svn.dealii.org/trunk@10165 0785d39b-7218-0410-832d-ea1e28bc413d

deal.II/base/include/base/smartpointer.h
deal.II/base/include/base/subscriptor.h
deal.II/base/source/subscriptor.cc
tests/base/reference.cc

index c2c8177dbc433cc39d5af6bac55ecb3b02f99434..cba0183ee88b6b709311fefd59f5abcee1e7de21 100644 (file)
@@ -2,7 +2,7 @@
 //    $Id$
 //    Version: $Name$
 //
-//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 by the deal authors
+//    Copyright (C) 1998 - 2005 by the deal authors
 //
 //    This file is subject to QPL and may not be  distributed
 //    without copyright and license information. Please refer
  * SmartPointer does NOT implement any memory handling! Especially,
  * deleting a SmartPointer does not delete the object. Writing
  * @code
- * SmartPointer<T> t = new T;
+ * SmartPointer<T> dont_do_this = new T;
  * @endcode
  * is a sure way to program a memory leak! The secure version is
  * @code
  * T* p = new T;
  * {
- *   SmartPointer<T> t = p;
+ *   SmartPointer<T> t(p, "mypointer");
  *   ...
  * }
  * delete p;
  * a constant object (disallowing write access when dereferenced), while
  * <tt>SmartPointer<ABC></tt> is a mutable pointer.
  *
- * @author Guido Kanschat, Wolfgang Bangerth, 1998, 1999, 2000
+ * @author Guido Kanschat, Wolfgang Bangerth, 1998 - 2005
  */
 template<typename T>
 class SmartPointer
 {
   public:
                                     /**
-                                     * Standard constructor for null pointer.
+                                     * Standard constructor for null
+                                     * pointer.  @deprecated Since
+                                     * this constructor will leave
+                                     * #id empty, it should be
+                                     * avoided wherever possible and
+                                     * replaced by SmartPointer(0,id).
                                      */
     SmartPointer ();
 
@@ -65,6 +70,11 @@ class SmartPointer
                                      * copy the object subscribed to
                                      * from <tt>tt</tt>, but subscribe
                                      * ourselves to it again.
+                                     *
+                                     * The <tt>id</tt> is used in the
+                                     * call to
+                                     * Subscriptor::subscribe(). The #id of
+                                     * the object copied is used here.
                                      */
     SmartPointer (const SmartPointer<T> &tt);
 
@@ -77,8 +87,14 @@ class SmartPointer
                                      * to lock it, i.e. to prevent
                                      * its destruction before the end
                                      * of its use.
+                                     *
+                                     * The <tt>id</tt> is used in the
+                                     * call to
+                                     * Subscriptor::subscribe() and
+                                     * by ~SmartPointer() in the call
+                                     * to Subscriptor::unsubscribe().
                                      */
-    SmartPointer (T *t);
+    SmartPointer (T *t, const char* id=0);
 
 
                                     /**
@@ -180,6 +196,11 @@ class SmartPointer
                                      * short name.
                                      */
     T * t;
+                                    /**
+                                     * The identification for the
+                                     * subscriptor.
+                                     */
+    const char* const id;
 };
 
 
@@ -189,18 +210,18 @@ class SmartPointer
 template <typename T>
 SmartPointer<T>::SmartPointer ()
                 :
-               t (0)
+               t (0), id(0)
 {}
 
 
 
 template <typename T>
-SmartPointer<T>::SmartPointer (T *t)
+SmartPointer<T>::SmartPointer (T *t, const char* id)
                 :
-               t (t)
+               t (t), id(id)
 {
   if (t != 0)
-    t->subscribe();
+    t->subscribe(id);
 }
 
 
@@ -208,7 +229,7 @@ SmartPointer<T>::SmartPointer (T *t)
 template <typename T>
 SmartPointer<T>::SmartPointer (const SmartPointer<T> &tt)
                 :
-               t (tt.t)
+               t (tt.t), id(tt.id)
 {
   if (t != 0)
     t->subscribe();
@@ -220,7 +241,7 @@ template <typename T>
 SmartPointer<T>::~SmartPointer ()
 {
   if (t != 0)
-    t->unsubscribe();
+    t->unsubscribe(id);
 }
 
 
@@ -234,10 +255,10 @@ SmartPointer<T> & SmartPointer<T>::operator = (T *tt)
     return *this;
   
   if (t != 0)
-    t->unsubscribe();
+    t->unsubscribe(id);
   t = tt;
   if (tt != 0)
-    tt->subscribe();
+    tt->subscribe(id);
   return *this;
 }
 
@@ -254,10 +275,10 @@ SmartPointer<T>::operator = (const SmartPointer<T>& tt)
     return *this;
   
   if (t != 0)
-    t->unsubscribe();
+    t->unsubscribe(id);
   t = static_cast<T*>(tt);
   if (tt != 0)
-    tt->subscribe();
+    tt->subscribe(id);
   return *this;
 }
 
index 003ad32c7843859cbdd7658e0ee739c328e1e97f..b9b44627981c33b0a950e714a87054bfb4bd081d 100644 (file)
@@ -2,7 +2,7 @@
 //    $Id$
 //    Version: $Name$
 //
-//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 by the deal.II authors
+//    Copyright (C) 1998 - 2005 by the deal.II authors
 //
 //    This file is subject to QPL and may not be  distributed
 //    without copyright and license information. Please refer
 
 #include <base/config.h>
 #include <base/exceptions.h>
-#include <typeinfo>
-
-
-namespace internal
-{
-                                  /**
-                                   * @internal
-                                   * A namespace in which we
-                                   * implement helper classes for the
-                                   * subscriptor class.
-                                   */
-  namespace Subscriptor
-  {
-                                     /**
-                                     * @internal
-                                      * Template class that declares
-                                      * in inner typedef with the
-                                      * following semantics: if the
-                                      * first template parameter is
-                                      * <tt>true</tt>, then the inner
-                                      * typedef is <tt>volatile T</tt>,
-                                      * otherwise <tt>T</tt>. We achieve
-                                      * this behavior by partial
-                                      * specialization of the general
-                                      * template for both values of
-                                      * the boolean argument.
-                                      *
-                                      * This trick is used to declare
-                                      * the type of the counter
-                                      * variable to be eiter volatile
-                                      * or not, depending on whether
-                                      * we are in multithreaded mode
-                                      * or not. (If we are in MT mode,
-                                      * then we need the <tt>volatile</tt>
-                                      * specifier since more than one
-                                      * thread my modify the counter
-                                      * at the same time.
-                                      *
-                                      * Since we only partially
-                                      * specialize the case that the
-                                      * boolean template argument is
-                                      * <tt>false</tt>, this general
-                                      * template catches the case that
-                                      * it is <tt>true</tt>, i.e. in a
-                                      * sense it is also a
-                                      * specialization since a
-                                      * <tt>bool</tt> can only have two
-                                      * states.
-                                      *
-                                      * @author Wolfgang Bangerth, 2003
-                                      */
-    template <bool, typename T> struct PossiblyVolatile
-    {
-                                        /**
-                                         * @internal
-                                         * @brief The actual typedef.
-                                         */
-        typedef volatile T type;
-    };
-
-                                     /**
-                                     * @internal
-                                      * Specialization of the template
-                                      * for the case that the first
-                                      * template argument is
-                                      * <tt>false</tt>, i.e. the
-                                      * non-volatile case.
-                                      */
-    template <typename T> struct PossiblyVolatile<false,T>
-    {
-                                        /**
-                                         * @internal
-                                         * @brief The actual typedef.
-                                         */
-        typedef T type;
-    };
-  }
-}
-
 
+#include <typeinfo>
+#include <map>
+#include <string>
 
 /**
  * Handling of subscriptions.
@@ -105,9 +29,23 @@ namespace internal
  * 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 <tt>subscribe</tt> to this object. The destructor the used
- * object inherits from the <tt>Subscriptor</tt> class then will lead to an error
+ * 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.
+ *
+ * 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. For reasons of efficiency, these
+ * strings are handled as <tt>const char*</tt>. 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.
+ *
+ * @note Due to a problem with <tt>volatile</tt> declarations, this
+ * additional feature is switched of if multithreading is used.
+ *
+ * @author Guido Kanschat, 1998 - 2005
  */
 class Subscriptor
 {
@@ -144,14 +82,24 @@ class Subscriptor
     Subscriptor& operator = (const Subscriptor&);
         
                                     /**
-                                     * Subscribes a user of the object.
+                                     * Subscribes a user of the
+                                     * object. The subscriber may be
+                                     * identified by text supplied as
+                                     * <tt>identifier</tt>.
                                      */
-    void subscribe () const;
+    void subscribe (const char* identifier = 0) const;
       
                                     /**
-                                     * Unsubscribes a user from the object.
+                                     * 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.
                                      */
-    void unsubscribe () const;
+    void unsubscribe (const char* identifier = 0) const;
 
                                     /**
                                      * Return the present number of
@@ -172,19 +120,46 @@ class Subscriptor
                                      * Object may not be deleted, since
                                      * it is used.
                                      */
-    DeclException2(ExcInUse,
-                  int, char *,
+    DeclException3(ExcInUse,
+                  int, char*, std::string&,
                   << "Object of class " << arg2
-                  << " is still used by " << arg1 << " other objects.");
+                  << " is still used by " << arg1 << " other objects."
+                  << arg3);
 
                                     /**
-                                     * Exception: object should be used
-                                     * when <tt>unsubscribe</tt> is called.
+                                     * A subscriber with the
+                                     * identification string given to
+                                     * Subscriptor::unsubscribe() did
+                                     * not subscribe to the object.
+                                     */
+    DeclException2(ExcNoSubscriber, char*, char*,
+                  << "No subscriber with identifier \"" << arg2
+                  << "\" did subscribe to this object of class " << arg1);
+    
+                                    /**
+                                     * Exception: object should be
+                                     * used when
+                                     * Subscriptor::unsubscribe() is
+                                     * called.
                                      */
     DeclException0(ExcNotUsed);
                                     //@}
 
   private:
+                                    /**
+                                     * The data type used in
+                                     * #counter_map.
+                                     */
+    typedef std::map<const char*, unsigned int>::value_type
+    map_value_type;
+    
+                                    /**
+                                     * The iterator type used in
+                                     * #counter_map.
+                                     */
+    typedef std::map<const char*, unsigned int>::iterator
+    map_iterator;
+    
                                     /**
                                      * Store the number of objects
                                      * which subscribed to this
@@ -196,7 +171,9 @@ class Subscriptor
                                      * unsubscribed again).
                                      *
                                      * The creator (and owner) of an
-                                     * object is not counted.
+                                     * object is counted in the map
+                                     * below if HE manages to supply
+                                     * identification.
                                      *
                                      * We use the <tt>mutable</tt> keyword
                                      * in order to allow subscription
@@ -209,12 +186,20 @@ class Subscriptor
                                      * <tt>volatile</tt>. However, this is
                                      * counter-productive in non-MT
                                      * mode since it may pessimize
-                                     * code. So use the above
-                                     * template class to selectively
+                                     * code. So use the macro
+                                     * defined above to selectively
                                      * add volatility.
                                      */
-    mutable internal::Subscriptor::PossiblyVolatile<DEAL_II_USE_MT,unsigned int>::type counter;
-
+    mutable DEAL_VOLATILE unsigned int counter;
+    
+                                    /**
+                                     * In this map, we count
+                                     * subscriptions for each
+                                     * different identification strig
+                                     * supplied to subscribe().
+                                     */
+    mutable std::map<const char*, unsigned int> counter_map;
+    
                                     /**
                                      * Pointer to the typeinfo object
                                      * of this object, from which we
@@ -229,5 +214,24 @@ class Subscriptor
     mutable const std::type_info * object_info;
 };
 
+//----------------------------------------------------------------------//
+
+// If we are in optimized mode, the subscription checking is turned
+// off. Therefore, we provide inline definitions of subscribe and
+// unsubscribe here. The definitions for debug mode are in
+// subscriptor.cc.
+
+#ifndef DEBUG
+
+inline void
+Subscriptor::subscribe(const char*) const
+{}
+
+
+inline void
+Subscriptor::unsubscribe(const char*) const
+{}
+
+#endif
 
 #endif
index 23c64e124044f86f34cb5b3ba992c9a6015691d4..90af76d623e5413e098202d39cbf7428e65fbf2f 100644 (file)
@@ -2,7 +2,7 @@
 //    $Id$
 //    Version: $Name$
 //
-//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 by the deal authors
+//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 by the deal authors
 //
 //    This file is subject to QPL and may not be  distributed
 //    without copyright and license information. Please refer
 
 #include <base/thread_management.h>
 #include <base/subscriptor.h>
+
 #include <typeinfo>
+#include <string>
+#include <iostream>
 
 namespace 
 {
@@ -31,57 +34,7 @@ namespace
 }
 
 
-
-/*
-#include <set>
-
-template <class Class>
-class ActiveObjectMonitor
-{
-  public:
-    ~ActiveObjectMonitor ();
-    
-    void register_object (const Class *p);
-    void deregister_object (const Class *p);
-  private:
-    std::set<const Class*> registered_objects;
-};
-
-ActiveObjectMonitor<Subscriptor> active_object_monitor;
-
-
-ActiveObjectMonitor::~ActiveObjectMonitor ()
-{
-  if (registered_objects.size() > 0)
-    {
-      for (typename std::set<const Subscriptor*>::const_iterator i=registered_objects.begin();
-          i!=registered_objects.end(); ++i)
-       std::cout << "Object still exists of type "
-                 << typeid(**i).name()
-                 << std::endl;
-      Assert (false, ExcInternalError());
-    };
-};
-
-
-void ActiveObjectMonitor::register_object (const Subscriptor *p)
-{
-  Assert (registered_objects.find(p) == registered_objects.end(),
-         ExcInternalError());
-  registered_objects.insert (p);
-};
-
-
-void
-ActiveObjectMonitor::deregister_object (const Subscriptor *p)
-{
-  Assert (registered_objects.find(p) != registered_objects.end(),
-         ExcInternalError());
-  registered_objects.erase (registered_objects.find(p));
-};
-*/
-
-
+static const char* unknown_subscriber = "unknown subscriber";
 
 
 Subscriptor::Subscriptor ()
@@ -111,7 +64,19 @@ Subscriptor::~Subscriptor ()
                                   // you can obtain the latter by
                                   // running the c++filt program over
                                   // the output.
-  Assert (counter == 0, ExcInUse(counter, object_info->name()));
+#ifdef DEBUG
+  std::string infostring;
+  for (map_iterator it = counter_map.begin(); it != counter_map.end(); ++it)
+    {
+      if (it->second > 0)
+       infostring += std::string("\n  from Subscriber ")
+                     + std::string(it->first);
+    }
+  
+  Assert (counter == 0, ExcInUse(counter,
+                                object_info->name(),
+                                infostring));
+#endif
 }
 
 
@@ -122,26 +87,47 @@ Subscriptor & Subscriptor::operator = (const Subscriptor &s)
   return *this;
 }
 
+// These are the implementations for debug mode. The optimized
+// versions are inlined in the header file.
 
-
-void Subscriptor::subscribe () const
-{
 #ifdef DEBUG
+void Subscriptor::subscribe (const char* id) const
+{
   if (object_info == 0)
     object_info = &typeid(*this);
-#endif
-
   Threads::ThreadMutex::ScopedLock lock (subscription_lock);
   ++counter;
+  
+#if DEAL_USE_MT == 0
+  const char* const name = (id != 0) ? id : unknown_subscriber;
+  
+  map_iterator it = counter_map.find(name);
+  if (it == counter_map.end())
+    counter_map.insert(map_value_type(name, 1U));
+  
+  else
+    it->second++;
+#endif
 }
 
 
-void Subscriptor::unsubscribe () const
+void Subscriptor::unsubscribe (const char* id) const
 {
   Assert (counter>0, ExcNotUsed());
   Threads::ThreadMutex::ScopedLock lock (subscription_lock);
   --counter;
+  
+#if DEAL_USE_MT == 0
+  const char* name = (id != 0) ? id : unknown_subscriber;
+
+  map_iterator it = counter_map.find(name);
+  Assert (it != counter_map.end(), ExcNoSubscriber(object_info->name(), name));
+  Assert (it->second > 0, ExcNoSubscriber(object_info->name(), name));
+  
+  it->second--;
+#endif
 }
+#endif
 
 
 unsigned int Subscriptor::n_subscriptions () const
index 64f1a8ac14dfd178b0c4e440ecc4f8d66eac4c20..1631ce677199b93072fb8d66994c310cb97a65cd 100644 (file)
@@ -2,7 +2,7 @@
 //    $Id$
 //    Version: $Name$ 
 //
-//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 by the deal.II authors
+//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by the deal.II authors
 //
 //    This file is subject to QPL and may not be  distributed
 //    without copyright and license information. Please refer
@@ -65,38 +65,38 @@ int main()
   streambuf *old_cerr_buf = std::cerr.rdbuf();
 #endif
   std::cerr.rdbuf(logfile.rdbuf());
-  
-  Test a("A");
-  const Test b("B");
-  SmartPointer<Test>       r=&a;
-  SmartPointer<const Test> s=&a;
-//  SmartPointer<Test>       t=&b;    // this one should not work
-  SmartPointer<Test>       t=const_cast<Test*>(&b);
-  SmartPointer<const Test> u=&b;
-
-
-  deallog << "a ";
-  a.f();            // should print "mutable", since #a# is not const
-  deallog << "b ";
-  b.f();            // should print "const", since #b# is const
-  deallog << "r ";
-  r->f();           // should print "mutable", since it points to the non-const #a#
-  deallog << "s ";
-  s->f();           // should print "const", since it points to the const #b#
-                                  // but we made it const
-  deallog << "t ";
-  t->f();           // should print "mutable", since #b# is const, but
-                                  // we casted the constness away
-  deallog << "u ";
-  u->f();           // should print "const" since #b# is const
-                                  // Now try if subscriptor works
-  {
-    Test c("C");
-    r = &c;
-    Test d("D");
-    r = &d;
-  }
 
+  if (true)
+    {
+      Test a("A");
+      const Test b("B");
+      SmartPointer<Test>       r(&a, "Test R");
+      SmartPointer<const Test> s(&a, "const Test S");
+//  SmartPointer<Test>       t=&b;    // this one should not work
+      SmartPointer<Test>       t(const_cast<Test*>(&b), "Test T");
+      SmartPointer<const Test> u(&b, "const Test");
+      
+      
+      deallog << "a ";
+      a.f();            // should print "mutable", since #a# is not const
+      deallog << "b ";
+      b.f();            // should print "const", since #b# is const
+      deallog << "r ";
+      r->f();           // should print "mutable", since it points to the non-const #a#
+      deallog << "s ";
+      s->f();           // should print "const", since it points to the const #b#
+                                      // but we made it const
+      deallog << "t ";
+      t->f();           // should print "mutable", since #b# is const, but
+                                      // we casted the constness away
+      deallog << "u ";
+      u->f();           // should print "const" since #b# is const
+                                      // Now try if subscriptor works
+      Test c("C");
+      r = &c;
+      Test d("D");
+      r = &d;
+    }
   std::cerr.rdbuf(old_cerr_buf);
 }
 

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.