From: Guido Kanschat Date: Wed, 16 Mar 2005 03:20:56 +0000 (+0000) Subject: New identification strings X-Git-Tag: v8.0.0~14371 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=819cf4f42840c28eaebac77939e887f2333ab9aa;p=dealii.git New identification strings git-svn-id: https://svn.dealii.org/trunk@10165 0785d39b-7218-0410-832d-ea1e28bc413d --- diff --git a/deal.II/base/include/base/smartpointer.h b/deal.II/base/include/base/smartpointer.h index c2c8177dbc..cba0183ee8 100644 --- a/deal.II/base/include/base/smartpointer.h +++ b/deal.II/base/include/base/smartpointer.h @@ -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 @@ -31,13 +31,13 @@ * SmartPointer does NOT implement any memory handling! Especially, * deleting a SmartPointer does not delete the object. Writing * @code - * SmartPointer t = new T; + * SmartPointer 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 = p; + * SmartPointer t(p, "mypointer"); * ... * } * delete p; @@ -48,14 +48,19 @@ * a constant object (disallowing write access when dereferenced), while * SmartPointer is a mutable pointer. * - * @author Guido Kanschat, Wolfgang Bangerth, 1998, 1999, 2000 + * @author Guido Kanschat, Wolfgang Bangerth, 1998 - 2005 */ template 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, but subscribe * ourselves to it again. + * + * The id is used in the + * call to + * Subscriptor::subscribe(). The #id of + * the object copied is used here. */ SmartPointer (const SmartPointer &tt); @@ -77,8 +87,14 @@ class SmartPointer * to lock it, i.e. to prevent * its destruction before the end * of its use. + * + * The id 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 SmartPointer::SmartPointer () : - t (0) + t (0), id(0) {} template -SmartPointer::SmartPointer (T *t) +SmartPointer::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::SmartPointer (T *t) template SmartPointer::SmartPointer (const SmartPointer &tt) : - t (tt.t) + t (tt.t), id(tt.id) { if (t != 0) t->subscribe(); @@ -220,7 +241,7 @@ template SmartPointer::~SmartPointer () { if (t != 0) - t->unsubscribe(); + t->unsubscribe(id); } @@ -234,10 +255,10 @@ SmartPointer & SmartPointer::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::operator = (const SmartPointer& tt) return *this; if (t != 0) - t->unsubscribe(); + t->unsubscribe(id); t = static_cast(tt); if (tt != 0) - tt->subscribe(); + tt->subscribe(id); return *this; } diff --git a/deal.II/base/include/base/subscriptor.h b/deal.II/base/include/base/subscriptor.h index 003ad32c78..b9b4462798 100644 --- a/deal.II/base/include/base/subscriptor.h +++ b/deal.II/base/include/base/subscriptor.h @@ -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 @@ -16,86 +16,10 @@ #include #include -#include - - -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 - * true, then the inner - * typedef is volatile T, - * otherwise T. 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 volatile - * 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 - * false, this general - * template catches the case that - * it is true, i.e. in a - * sense it is also a - * specialization since a - * bool can only have two - * states. - * - * @author Wolfgang Bangerth, 2003 - */ - template 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 - * false, i.e. the - * non-volatile case. - */ - template struct PossiblyVolatile - { - /** - * @internal - * @brief The actual typedef. - */ - typedef T type; - }; - } -} - +#include +#include +#include /** * 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 subscribe to this object. The destructor the used - * object inherits from the Subscriptor 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 const char*. 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 volatile 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 + * identifier. */ - void subscribe () const; + void subscribe (const char* identifier = 0) const; /** - * Unsubscribes a user from the object. + * 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. */ - 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 unsubscribe 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::value_type + map_value_type; + + /** + * The iterator type used in + * #counter_map. + */ + typedef std::map::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 mutable keyword * in order to allow subscription @@ -209,12 +186,20 @@ class Subscriptor * volatile. 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::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 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 diff --git a/deal.II/base/source/subscriptor.cc b/deal.II/base/source/subscriptor.cc index 23c64e1240..90af76d623 100644 --- a/deal.II/base/source/subscriptor.cc +++ b/deal.II/base/source/subscriptor.cc @@ -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 @@ -14,7 +14,10 @@ #include #include + #include +#include +#include namespace { @@ -31,57 +34,7 @@ namespace } - -/* -#include - -template -class ActiveObjectMonitor -{ - public: - ~ActiveObjectMonitor (); - - void register_object (const Class *p); - void deregister_object (const Class *p); - private: - std::set registered_objects; -}; - -ActiveObjectMonitor active_object_monitor; - - -ActiveObjectMonitor::~ActiveObjectMonitor () -{ - if (registered_objects.size() > 0) - { - for (typename std::set::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 diff --git a/tests/base/reference.cc b/tests/base/reference.cc index 64f1a8ac14..1631ce6771 100644 --- a/tests/base/reference.cc +++ b/tests/base/reference.cc @@ -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 r=&a; - SmartPointer s=&a; -// SmartPointer t=&b; // this one should not work - SmartPointer t=const_cast(&b); - SmartPointer 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 r(&a, "Test R"); + SmartPointer s(&a, "const Test S"); +// SmartPointer t=&b; // this one should not work + SmartPointer t(const_cast(&b), "Test T"); + SmartPointer 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); }