Teuchos - Trilinos Tools Package Version of the Day
Teuchos_RCPNode.cpp
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00025 //
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 #include "Teuchos_RCPNode.hpp"
00030 #include "Teuchos_TestForException.hpp"
00031 #include "Teuchos_Exceptions.hpp"
00032 
00033 
00034 // Defined this to see tracing of RCPNodes created and destroyed
00035 //#define RCP_NODE_DEBUG_TRACE_PRINT
00036 
00037 
00038 //
00039 // Internal implementatation stuff
00040 //
00041 
00042 
00043 namespace {
00044 
00045 
00046 //
00047 // Local implementation types
00048 //
00049 
00050 
00051 struct RCPNodeInfo {
00052   RCPNodeInfo() : nodePtr(0) {}
00053   RCPNodeInfo(const std::string &info_in, Teuchos::RCPNode* nodePtr_in)
00054     : info(info_in), nodePtr(nodePtr_in)
00055     {}
00056   std::string info;
00057   Teuchos::RCPNode* nodePtr;
00058 };
00059 
00060 
00061 typedef std::pair<const void*, RCPNodeInfo> VoidPtrNodeRCPInfoPair_t;
00062 
00063 
00064 typedef std::multimap<const void*, RCPNodeInfo> rcp_node_list_t;
00065 
00066 
00067 class RCPNodeInfoListPred {
00068 public:
00069   bool operator()(const rcp_node_list_t::value_type &v1,
00070     const rcp_node_list_t::value_type &v2
00071     ) const
00072     {
00073 #ifdef TEUCHOS_DEBUG
00074       return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number();
00075 #else
00076       return v1.first < v2.first;
00077 #endif
00078     }
00079 };
00080 
00081 
00082 //
00083 // Local static functions returning references to local static objects to
00084 // ensure objects are initilaized.
00085 //
00086 // Technically speaking, the static functions on RCPNodeTracer that use this
00087 // data might be called from other translation units in pre-main code before
00088 // this translation unit gets initialized.  By using functions returning
00089 // references to local static varible trick, we ensure that these objects are
00090 // always initialized before they are used, no matter what.
00091 //
00092 // These could have been static functions on RCPNodeTracer but the advantage
00093 // of defining these functions this way is that you can add and remove
00094 // functions without affecting the *.hpp file and therefore avoid
00095 // recompilation (and even relinking with shared libraries).
00096 //
00097 
00098 
00099 rcp_node_list_t*& rcp_node_list()
00100 {
00101   static rcp_node_list_t *s_rcp_node_list = 0;
00102   // Here we must let the ActiveRCPNodesSetup constructor and destructor handle
00103   // the creation and destruction of this map object.  This will ensure that
00104   // this map object will be valid when any global/static RCP objects are
00105   // destroyed!  Note that this object will get created and destroyed
00106   // reguardless if whether we are tracing RCPNodes or not.  This just makes our
00107   // life simpler.  NOTE: This list will always get allocated no mater if
00108   // TEUCHOS_DEBUG is defined or node traceing is enabled or not.
00109   return s_rcp_node_list;
00110 }
00111 
00112 
00113 bool& loc_isTracingActiveRCPNodes()
00114 {
00115   static bool s_loc_isTracingActiveRCPNodes =
00116 #if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
00117     true
00118 #else
00119     false
00120 #endif
00121     ;
00122   return s_loc_isTracingActiveRCPNodes;
00123 }
00124 
00125 
00126 Teuchos::RCPNodeTracer::RCPNodeStatistics& loc_rcpNodeStatistics()
00127 {
00128   static Teuchos::RCPNodeTracer::RCPNodeStatistics s_loc_rcpNodeStatistics;
00129   return s_loc_rcpNodeStatistics;
00130 }
00131 
00132 
00133 bool& loc_printRCPNodeStatisticsOnExit()
00134 {
00135   static bool s_loc_printRCPNodeStatisticsOnExit = false;
00136   return s_loc_printRCPNodeStatisticsOnExit;
00137 }
00138 
00139 
00140 //
00141 // Other helper functions
00142 //
00143 
00144 // This function returns the const void* value that is used as the key to look
00145 // up an RCPNode object that has been stored.  If the RCPNode is holding a
00146 // non-null reference, then we use that object address as the key.  That way,
00147 // we can detect if a user trys to create a new owning RCPNode to the same
00148 // object.  If the RCPNode has an null internal object pointer, then we will
00149 // use the RCPNode's address itself.  In this case, we want to check and see
00150 // that all RCPNodes that get created get destroyed correctly.
00151 const void* get_map_key_void_ptr(const Teuchos::RCPNode* rcp_node)
00152 {
00153   TEUCHOS_ASSERT(rcp_node);
00154 #ifdef TEUCHOS_DEBUG
00155   const void* base_obj_map_key_void_ptr = rcp_node->get_base_obj_map_key_void_ptr();
00156   if (base_obj_map_key_void_ptr)
00157     return base_obj_map_key_void_ptr;
00158 #endif
00159   return rcp_node;
00160 }
00161 
00162 
00163 std::string convertRCPNodeToString(const Teuchos::RCPNode* rcp_node)
00164 {
00165   std::ostringstream oss;
00166   oss
00167     << "RCPNode {address="
00168     << rcp_node
00169 #ifdef TEUCHOS_DEBUG
00170     << ", base_obj_map_key_void_ptr=" << rcp_node->get_base_obj_map_key_void_ptr()
00171 #endif
00172     << ", base_obj_type_name=" << rcp_node->get_base_obj_type_name()
00173     << ", map_key_void_ptr=" << get_map_key_void_ptr(rcp_node)
00174     << ", has_ownership=" << rcp_node->has_ownership()
00175 #ifdef TEUCHOS_DEBUG
00176     << ", insertionNumber="<< rcp_node->insertion_number()
00177 #endif
00178     << "}";
00179   return oss.str();
00180 }
00181 
00182 
00183 } // namespace
00184 
00185 
00186 namespace Teuchos {
00187 
00188 
00189 //
00190 // RCPNode
00191 //
00192 
00193 
00194 void RCPNode::set_extra_data(
00195   const any &extra_data, const std::string& name
00196   ,EPrePostDestruction destroy_when
00197   ,bool force_unique
00198   )
00199 {
00200   if(extra_data_map_==NULL) {
00201     extra_data_map_ = new extra_data_map_t;
00202   }
00203   const std::string type_and_name( extra_data.typeName() + std::string(":") + name );
00204   extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
00205 #ifdef TEUCHOS_DEBUG
00206   TEST_FOR_EXCEPTION(
00207     (itr != extra_data_map_->end() && force_unique), std::invalid_argument
00208     ,"Error, the type:name pair \'" << type_and_name
00209     << "\' already exists and force_unique==true!" );
00210 #endif
00211   if (itr != extra_data_map_->end()) {
00212     // Change existing extra data
00213     itr->second = extra_data_entry_t(extra_data,destroy_when);
00214   }
00215   else {
00216     // Insert new extra data
00217     (*extra_data_map_)[type_and_name] =
00218       extra_data_entry_t(extra_data,destroy_when);
00219   }
00220 }
00221 
00222 
00223 any& RCPNode::get_extra_data( const std::string& type_name, const std::string& name )
00224 {
00225 #ifdef TEUCHOS_DEBUG
00226   TEST_FOR_EXCEPTION(
00227     extra_data_map_==NULL, std::invalid_argument
00228     ,"Error, no extra data has been set yet!" );
00229 #endif
00230   any *extra_data = get_optional_extra_data(type_name,name);
00231 #ifdef TEUCHOS_DEBUG
00232   if (!extra_data) {
00233     const std::string type_and_name( type_name + std::string(":") + name );
00234     TEST_FOR_EXCEPTION(
00235       extra_data == NULL, std::invalid_argument
00236       ,"Error, the type:name pair \'" << type_and_name << "\' is not found!" );
00237   }
00238 #endif
00239   return *extra_data;
00240 }
00241 
00242 
00243 any* RCPNode::get_optional_extra_data( const std::string& type_name,
00244   const std::string& name )
00245 {
00246   if( extra_data_map_ == NULL ) return NULL;
00247   const std::string type_and_name( type_name + std::string(":") + name );
00248   extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
00249   if(itr != extra_data_map_->end())
00250     return &(*itr).second.extra_data;
00251   return NULL;
00252 }
00253 
00254 
00255 void RCPNode::impl_pre_delete_extra_data()
00256 {
00257   for(
00258     extra_data_map_t::iterator itr = extra_data_map_->begin();
00259     itr != extra_data_map_->end();
00260     ++itr
00261     )
00262   {
00263     extra_data_map_t::value_type &entry = *itr;
00264     if(entry.second.destroy_when == PRE_DESTROY)
00265       entry.second.extra_data = any();
00266   }
00267 }
00268 
00269 
00270 //
00271 // RCPNodeTracer
00272 //
00273 
00274 
00275 // General user functions
00276 
00277 
00278 bool RCPNodeTracer::isTracingActiveRCPNodes()
00279 {
00280   return loc_isTracingActiveRCPNodes();
00281 }
00282 
00283 
00284 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
00285 void RCPNodeTracer::setTracingActiveRCPNodes(bool tracingActiveNodes)
00286 {
00287   loc_isTracingActiveRCPNodes() = tracingActiveNodes;
00288 }
00289 #endif
00290 
00291 
00292 int RCPNodeTracer::numActiveRCPNodes()
00293 {
00294   // This list always exists, no matter debug or not so just access it.
00295   TEST_FOR_EXCEPT(0==rcp_node_list());
00296   return rcp_node_list()->size();
00297   return 0;
00298 }
00299 
00300 
00301 RCPNodeTracer::RCPNodeStatistics
00302 RCPNodeTracer::getRCPNodeStatistics()
00303 {
00304   return loc_rcpNodeStatistics();
00305 }
00306 
00307 void RCPNodeTracer::printRCPNodeStatistics(
00308     const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out)
00309 {
00310   out
00311     << "\n***"
00312     << "\n*** RCPNode Tracing statistics:"
00313     << "\n**\n"
00314     << "\n    maxNumRCPNodes             = "<<rcpNodeStatistics.maxNumRCPNodes
00315     << "\n    totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
00316     << "\n    totalNumRCPNodeDeletions   = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
00317     << "\n";
00318 }
00319 
00320 
00321 void RCPNodeTracer::setPrintRCPNodeStatisticsOnExit(
00322   bool printRCPNodeStatisticsOnExit)
00323 {
00324   loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
00325 }
00326 
00327 
00328 bool RCPNodeTracer::getPrintRCPNodeStatisticsOnExit()
00329 {
00330   return loc_printRCPNodeStatisticsOnExit();
00331 }
00332 
00333 
00334 void RCPNodeTracer::printActiveRCPNodes(std::ostream &out)
00335 {
00336 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00337   out
00338     << "\nCalled printActiveRCPNodes() :"
00339     << " rcp_node_list.size() = " << rcp_node_list().size() << "\n";
00340 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00341   if (loc_isTracingActiveRCPNodes()) {
00342     TEST_FOR_EXCEPT(0==rcp_node_list());
00343     if (rcp_node_list()->size() > 0) {
00344       out << getActiveRCPNodeHeaderString();
00345       // Create a sorted-by-insertionNumber list
00346       // NOTE: You have to use std::vector and *not* Teuchos::Array rcp here
00347       // because this called at the very end and uses RCPNode itself in a
00348       // debug-mode build.
00349       typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t;
00350       rcp_node_vec_t rcp_node_vec(rcp_node_list()->begin(), rcp_node_list()->end());
00351       std::sort(rcp_node_vec.begin(), rcp_node_vec.end(), RCPNodeInfoListPred());
00352       // Print the RCPNode objects sorted by insertion number
00353       typedef rcp_node_vec_t::const_iterator itr_t;
00354       int i = 0;
00355       for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) {
00356         const rcp_node_list_t::value_type &entry = *itr;
00357         TEUCHOS_ASSERT(entry.second.nodePtr);
00358         out
00359           << "\n"
00360           << std::setw(3) << std::right << i << std::left
00361           << ": RCPNode (map_key_void_ptr=" << entry.first << ")\n"
00362           << "       Information = " << entry.second.info << "\n"
00363           << "       RCPNode address = " << entry.second.nodePtr << "\n"
00364 #ifdef TEUCHOS_DEBUG
00365           << "       insertionNumber = " << entry.second.nodePtr->insertion_number()
00366 #endif
00367           ;
00368         ++i;
00369       }
00370       out << "\n\n"
00371           << getCommonDebugNotesString();
00372     }
00373   }
00374 }
00375 
00376 
00377 // Internal implementation functions
00378 
00379 
00380 void RCPNodeTracer::addNewRCPNode( RCPNode* rcp_node, const std::string &info )
00381 {
00382 
00383   // Used to allow unique identification of rcp_node to allow setting breakpoints
00384   static int insertionNumber = 0;
00385 
00386   // Set the insertion number right away in case an exception gets thrown so
00387   // that you can set a break point to debug this.
00388 #ifdef TEUCHOS_DEBUG
00389   rcp_node->set_insertion_number(insertionNumber);
00390 #endif
00391 
00392   if (loc_isTracingActiveRCPNodes()) {
00393 
00394     // Print the node we are adding if configured to do so.  We have to send
00395     // to std::cerr to make sure that this gets printed.
00396 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
00397     std::cerr
00398       << "RCPNodeTracer::addNewRCPNode(...): Adding "
00399       << convertRCPNodeToString(rcp_node) << " ...\n";
00400 #endif
00401 
00402     TEST_FOR_EXCEPT(0==rcp_node_list());
00403 
00404     const void * const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
00405     
00406     // See if the rcp_node or its object has already been added.
00407     typedef rcp_node_list_t::iterator itr_t;
00408     typedef std::pair<itr_t, itr_t> itr_itr_t;
00409     const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr);
00410     const bool rcp_node_already_exists = itr_itr.first != itr_itr.second;
00411     RCPNode *previous_rcp_node = 0;
00412     bool previous_rcp_node_has_ownership = false;
00413     for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
00414       previous_rcp_node = itr->second.nodePtr;
00415       if (previous_rcp_node->has_ownership()) {
00416         previous_rcp_node_has_ownership = true;
00417         break;
00418       }
00419     }
00420     TEST_FOR_EXCEPTION(
00421       rcp_node_already_exists && rcp_node->has_ownership() && previous_rcp_node_has_ownership,
00422       DuplicateOwningRCPError,
00423       "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n"
00424       "RCPNode object to an existing managed object in another RCPNode:\n"
00425       "\n"
00426       "  New " << convertRCPNodeToString(rcp_node) << "\n"
00427       "\n"
00428       "  Existing " << convertRCPNodeToString(previous_rcp_node) << "\n"
00429       "\n"
00430       "  Number current nodes = " << rcp_node_list()->size() << "\n"
00431       "\n"
00432       "This may indicate that the user might be trying to create a weak RCP to an existing\n"
00433       "object but forgot make it non-ownning.  Perhaps they meant to use rcpFromRef(...)\n"
00434       "or an equivalent function?\n"
00435       "\n"
00436       << getCommonDebugNotesString();
00437       );
00438 
00439     // NOTE: We allow duplicate RCPNodes if the new node is non-owning.  This
00440     // might indicate a advanced usage of the RCP class that we want to
00441     // support.  The typical problem is when the programmer unknowingly
00442     // creates an owning RCP to an object already owned by another RCPNode.
00443 
00444     // Add the new RCP node keyed as described above.
00445     (*rcp_node_list()).insert(
00446       itr_itr.second,
00447       std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
00448       );
00449     // NOTE: Above, if there is already an existing RCPNode with the same key
00450     // value, this iterator itr_itr.second will point to one after the found
00451     // range.  I suspect that this might also ensure that the elements are
00452     // sorted in natural order.
00453 
00454     // Update the insertion number an node tracing statistics
00455     ++insertionNumber;
00456     ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
00457     loc_rcpNodeStatistics().maxNumRCPNodes =
00458       TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes());
00459   }
00460 }
00461 
00462 
00463 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
00464   TEST_FOR_EXCEPTION((CONDITION), \
00465     std::logic_error, \
00466     "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \
00467     << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \
00468     " active RCP nodes being traced even though all nodes should be traced." \
00469     "  This should not be possible and can only be an internal programming error!")
00470 
00471 
00472 void RCPNodeTracer::removeRCPNode( RCPNode* rcp_node )
00473 {
00474 
00475   // Here, we will try to remove an RCPNode reguardless if whether
00476   // loc_isTracingActiveRCPNodes==true or not.  This will not be a performance
00477   // problem and it will ensure that any RCPNode objects that are added to
00478   // this list will be removed and will not look like a memory leak.  In
00479   // non-debug mode, this function will never be called.  In debug mode, with
00480   // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
00481   // therefore this find(...) operation should be pretty cheap (even for a bad
00482   // implementation of std::map).
00483 
00484   TEUCHOS_ASSERT(rcp_node_list());
00485   typedef rcp_node_list_t::iterator itr_t;
00486   typedef std::pair<itr_t, itr_t> itr_itr_t;
00487 
00488   const itr_itr_t itr_itr =
00489     rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node));
00490   const bool rcp_node_exists = itr_itr.first != itr_itr.second;
00491 
00492 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
00493   // If we have the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned on a
00494   // compile time, then all RCPNode objects that get created will have been
00495   // added to this list.  In this case, we can asset that the node exists.
00496   TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
00497 #else
00498   // If the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned off, then is is
00499   // possible that an RCP got created before the bool
00500   // loc_isTracingActiveRCPNodes was turned on.  In this case, we must allow
00501   // for an RCP node not to have been added to this list.  In this case we
00502   // will just let this go!
00503 #endif
00504 
00505   if (rcp_node_exists) {
00506 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
00507     std::cerr
00508       << "RCPNodeTracer::removeRCPNode(...): Removing "
00509       << convertRCPNodeToString(rcp_node) << " ...\n";
00510 #endif
00511     bool foundRCPNode = false;
00512     for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
00513       if (itr->second.nodePtr == rcp_node) {
00514         rcp_node_list()->erase(itr);
00515         ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions;
00516         foundRCPNode = true;
00517         break;
00518       }
00519     }
00520     // Whoops! Did not find the node!
00521     TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
00522   }
00523 
00524 }
00525 
00526 
00527 RCPNode* RCPNodeTracer::getExistingRCPNodeGivenLookupKey(const void* p)
00528 {
00529   typedef rcp_node_list_t::iterator itr_t;
00530   typedef std::pair<itr_t, itr_t> itr_itr_t;
00531   if (!p)
00532     return 0;
00533   const itr_itr_t itr_itr = rcp_node_list()->equal_range(p);
00534   for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
00535     RCPNode* rcpNode = itr->second.nodePtr;
00536     if (rcpNode->has_ownership()) {
00537       return rcpNode;
00538     }
00539   }
00540   return 0;
00541   // NOTE: Above, we return the first RCPNode added that has the given key
00542   // value.  
00543 }
00544 
00545 
00546 std::string RCPNodeTracer::getActiveRCPNodeHeaderString()
00547 {
00548   return std::string(
00549     "\n***"
00550     "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
00551     "\n*** not been destroyed yet.  A memory checking tool may complain that these"
00552     "\n*** objects are not destroyed correctly."
00553     "\n***"
00554     "\n*** There can be many possible reasons that this might occur including:"
00555     "\n***"
00556     "\n***   a) The program called abort() or exit() before main() was finished."
00557     "\n***      All of the objects that would have been freed through destructors"
00558     "\n***      are not freed but some compilers (e.g. GCC) will still call the"
00559     "\n***      destructors on static objects (which is what causes this message"
00560     "\n***      to be printed)."
00561     "\n***"
00562     "\n***   b) The program is using raw new/delete to manage some objects and"
00563     "\n***      delete was not called correctly and the objects not deleted hold"
00564     "\n***      other objects through reference-counted pointers."
00565     "\n***"
00566     "\n***   c) This may be an indication that these objects may be involved in"
00567     "\n***      a circular dependency of reference-counted managed objects."
00568     "\n***\n"
00569     );
00570 }
00571 
00572 
00573 std::string RCPNodeTracer::getCommonDebugNotesString()
00574 {
00575   return std::string(
00576     "NOTE: To debug issues, open a debugger, and set a break point in the function where\n"
00577     "the RCPNode object is first created to determine the context where the object first\n"
00578     "gets created.  Each RCPNode object is given a unique insertionNumber to allow setting\n"
00579     "breakpoints in the code.  For example, in GDB one can perform:\n"
00580     "\n"
00581     "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
00582     "\n"
00583     "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n"
00584     "inserted.  In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n"
00585     "\n"
00586     "  (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] [ENTER]\n"
00587     "  (gdb) cond 1 insertionNumber==3 [ENTER]\n"
00588     "\n"
00589     "3) Run the program in the debugger.  In GDB, do:\n"
00590     "\n"
00591     "  (gdb) run [ENTER]\n"
00592     "\n"
00593     "4) Examine the call stack when the prgoram breaks in the function addNewRCPNode(...)\n"
00594     );
00595 }
00596 
00597 
00598 //
00599 // ActiveRCPNodesSetup
00600 //
00601 
00602 
00603 ActiveRCPNodesSetup::ActiveRCPNodesSetup()
00604 {
00605 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00606   std::cerr << "\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ << "\n";
00607 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00608   if (!rcp_node_list())
00609     rcp_node_list() = new rcp_node_list_t;
00610   ++count_;
00611 }
00612 
00613 
00614 ActiveRCPNodesSetup::~ActiveRCPNodesSetup()
00615 {
00616 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00617   std::cerr << "\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ << "\n";
00618 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00619   if( --count_ == 0 ) {
00620 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00621     std::cerr << "\nPrint active nodes!\n";
00622 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00623     std::cout << std::flush;
00624     TEST_FOR_EXCEPT(0==rcp_node_list());
00625     RCPNodeTracer::RCPNodeStatistics rcpNodeStatistics =
00626       RCPNodeTracer::getRCPNodeStatistics();
00627     if (rcpNodeStatistics.maxNumRCPNodes
00628       && RCPNodeTracer::getPrintRCPNodeStatisticsOnExit())
00629     {
00630       RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout);
00631     }
00632     RCPNodeTracer::printActiveRCPNodes(std::cerr);
00633     delete rcp_node_list();
00634     rcp_node_list() = 0;
00635   }
00636 }
00637 
00638 
00639 void Teuchos::ActiveRCPNodesSetup::foo()
00640 {
00641   int dummy = count_;
00642   ++dummy; // Avoid unused variable warning (bug 2664)
00643 }
00644 
00645 
00646 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
00647 
00648 
00649 //
00650 // RCPNodeHandle
00651 //
00652 
00653 
00654 void RCPNodeHandle::unbindOne()
00655 {
00656   if (node_) {
00657     // NOTE: We only deincrement the reference count after
00658     // we have called delete on the underlying object since
00659     // that call to delete may actually thrown an exception!
00660     if (node_->strong_count()==1 && strength()==RCP_STRONG) {
00661       // Delete the object (which might throw)
00662       node_->delete_obj();
00663  #ifdef TEUCHOS_DEBUG
00664       // We actaully also need to remove the RCPNode from the active list for
00665       // some specialized use cases that need to be able to create a new RCP
00666       // node pointing to the same memory.  What this means is that when the
00667       // strong count goes to zero and the referenced object is destroyed,
00668       // then it will not longer be picked up by any other code and instead it
00669       // will only be known by its remaining weak RCPNodeHandle objects in
00670       // order to perform debug-mode runtime checking in case a client tries
00671       // to access the obejct.
00672       local_activeRCPNodesSetup.foo(); // Make sure created!
00673       RCPNodeTracer::removeRCPNode(node_);
00674 #endif
00675    }
00676     // If we get here, no exception was thrown!
00677     if ( (node_->strong_count() + node_->weak_count()) == 1 ) {
00678       // The last RCP object is going away so time to delete
00679       // the entire node!
00680       delete node_;
00681       node_ = 0;
00682       // NOTE: No need to deincrement the reference count since this is
00683       // the last RCP object being deleted!
00684     }
00685     else {
00686       // The last RCP has not gone away so just deincrement the reference
00687       // count.
00688       node_->deincr_count(strength());
00689     }
00690   }
00691 }
00692 
00693 
00694 } // namespace Teuchos
00695 
00696 
00697 //
00698 // Non-member helpers
00699 //
00700 
00701 
00702 void Teuchos::throw_null_ptr_error( const std::string &type_name )
00703 {
00704   TEST_FOR_EXCEPTION(
00705     true, NullReferenceError, 
00706     type_name << " : You can not call operator->() or operator*()"
00707     <<" if getRawPtr()==0!" );
00708 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines