Teuchos_RCPNode.cpp

Go to the documentation of this file.
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   if( !extra_data_map_->empty() && force_unique ) {
00205     extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
00206 #ifdef TEUCHOS_DEBUG
00207     TEST_FOR_EXCEPTION(
00208       itr != extra_data_map_->end(), std::invalid_argument
00209       ,"Error, the type:name pair \'" << type_and_name
00210       << "\' already exists and force_unique==true!" );
00211 #endif
00212   }
00213   (*extra_data_map_)[type_and_name] =
00214     extra_data_entry_t(extra_data,destroy_when); // This may add or replace!
00215 }
00216 
00217 
00218 any& RCPNode::get_extra_data( const std::string& type_name, const std::string& name )
00219 {
00220 #ifdef TEUCHOS_DEBUG
00221   TEST_FOR_EXCEPTION(
00222     extra_data_map_==NULL, std::invalid_argument
00223     ,"Error, no extra data has been set yet!" );
00224 #endif
00225   any *extra_data = get_optional_extra_data(type_name,name);
00226 #ifdef TEUCHOS_DEBUG
00227   if (!extra_data) {
00228     const std::string type_and_name( type_name + std::string(":") + name );
00229     TEST_FOR_EXCEPTION(
00230       extra_data == NULL, std::invalid_argument
00231       ,"Error, the type:name pair \'" << type_and_name << "\' is not found!" );
00232   }
00233 #endif
00234   return *extra_data;
00235 }
00236 
00237 
00238 any* RCPNode::get_optional_extra_data( const std::string& type_name,
00239   const std::string& name )
00240 {
00241   if( extra_data_map_ == NULL ) return NULL;
00242   const std::string type_and_name( type_name + std::string(":") + name );
00243   extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
00244   if(itr != extra_data_map_->end())
00245     return &(*itr).second.extra_data;
00246   return NULL;
00247 }
00248 
00249 
00250 void RCPNode::impl_pre_delete_extra_data()
00251 {
00252   for(
00253     extra_data_map_t::iterator itr = extra_data_map_->begin();
00254     itr != extra_data_map_->end();
00255     ++itr
00256     )
00257   {
00258     extra_data_map_t::value_type &entry = *itr;
00259     if(entry.second.destroy_when == PRE_DESTROY)
00260       entry.second.extra_data = any();
00261   }
00262 }
00263 
00264 
00265 //
00266 // RCPNodeTracer
00267 //
00268 
00269 
00270 // General user functions
00271 
00272 
00273 bool RCPNodeTracer::isTracingActiveRCPNodes()
00274 {
00275   return loc_isTracingActiveRCPNodes();
00276 }
00277 
00278 
00279 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
00280 void RCPNodeTracer::setTracingActiveRCPNodes(bool tracingActiveNodes)
00281 {
00282   loc_isTracingActiveRCPNodes() = tracingActiveNodes;
00283 }
00284 #endif
00285 
00286 
00287 int RCPNodeTracer::numActiveRCPNodes()
00288 {
00289   // This list always exists, no matter debug or not so just access it.
00290   TEST_FOR_EXCEPT(0==rcp_node_list());
00291   return rcp_node_list()->size();
00292   return 0;
00293 }
00294 
00295 
00296 RCPNodeTracer::RCPNodeStatistics
00297 RCPNodeTracer::getRCPNodeStatistics()
00298 {
00299   return loc_rcpNodeStatistics();
00300 }
00301 
00302 void RCPNodeTracer::printRCPNodeStatistics(
00303     const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out)
00304 {
00305   out
00306     << "\n***"
00307     << "\n*** RCPNode Tracing statistics:"
00308     << "\n**\n"
00309     << "\n    maxNumRCPNodes             = "<<rcpNodeStatistics.maxNumRCPNodes
00310     << "\n    totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
00311     << "\n    totalNumRCPNodeDeletions   = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
00312     << "\n";
00313 }
00314 
00315 
00316 void RCPNodeTracer::setPrintRCPNodeStatisticsOnExit(
00317   bool printRCPNodeStatisticsOnExit)
00318 {
00319   loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
00320 }
00321 
00322 
00323 bool RCPNodeTracer::getPrintRCPNodeStatisticsOnExit()
00324 {
00325   return loc_printRCPNodeStatisticsOnExit();
00326 }
00327 
00328 
00329 void RCPNodeTracer::printActiveRCPNodes(std::ostream &out)
00330 {
00331 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00332   out
00333     << "\nCalled printActiveRCPNodes() :"
00334     << " rcp_node_list.size() = " << rcp_node_list().size() << "\n";
00335 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00336   if (loc_isTracingActiveRCPNodes()) {
00337     TEST_FOR_EXCEPT(0==rcp_node_list());
00338     if (rcp_node_list()->size() > 0) {
00339       out << getActiveRCPNodeHeaderString();
00340       // Create a sorted-by-insertionNumber list
00341       // NOTE: You have to use std::vector and *not* Teuchos::Array rcp here
00342       // because this called at the very end and uses RCPNode itself in a
00343       // debug-mode build.
00344       typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t;
00345       rcp_node_vec_t rcp_node_vec(rcp_node_list()->begin(), rcp_node_list()->end());
00346       std::sort(rcp_node_vec.begin(), rcp_node_vec.end(), RCPNodeInfoListPred());
00347       // Print the RCPNode objects sorted by insertion number
00348       typedef rcp_node_vec_t::const_iterator itr_t;
00349       int i = 0;
00350       for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) {
00351         const rcp_node_list_t::value_type &entry = *itr;
00352         TEUCHOS_ASSERT(entry.second.nodePtr);
00353         out
00354           << "\n"
00355           << std::setw(3) << std::right << i << std::left
00356           << ": RCPNode (map_key_void_ptr=" << entry.first << ")\n"
00357           << "       Information = " << entry.second.info << "\n"
00358           << "       RCPNode address = " << entry.second.nodePtr << "\n"
00359 #ifdef TEUCHOS_DEBUG
00360           << "       insertionNumber = " << entry.second.nodePtr->insertion_number()
00361 #endif
00362           ;
00363         ++i;
00364       }
00365       out << "\n\n"
00366           << getCommonDebugNotesString();
00367     }
00368   }
00369 }
00370 
00371 
00372 // Internal implementation functions
00373 
00374 
00375 void RCPNodeTracer::addNewRCPNode( RCPNode* rcp_node, const std::string &info )
00376 {
00377 
00378   // Used to allow unique identification of rcp_node to allow setting breakpoints
00379   static int insertionNumber = 0;
00380 
00381   // Set the insertion number right away in case an exception gets thrown so
00382   // that you can set a break point to debug this.
00383 #ifdef TEUCHOS_DEBUG
00384   rcp_node->set_insertion_number(insertionNumber);
00385 #endif
00386 
00387   if (loc_isTracingActiveRCPNodes()) {
00388 
00389     // Print the node we are adding if configured to do so.  We have to send
00390     // to std::cerr to make sure that this gets printed.
00391 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
00392     std::cerr
00393       << "RCPNodeTracer::addNewRCPNode(...): Adding "
00394       << convertRCPNodeToString(rcp_node) << " ...\n";
00395 #endif
00396 
00397     TEST_FOR_EXCEPT(0==rcp_node_list());
00398 
00399     const void * const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
00400     
00401     // See if the rcp_node or its object has already been added.
00402     typedef rcp_node_list_t::iterator itr_t;
00403     typedef std::pair<itr_t, itr_t> itr_itr_t;
00404     const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr);
00405     const bool rcp_node_already_exists = itr_itr.first != itr_itr.second;
00406     RCPNode *previous_rcp_node = 0;
00407     bool previous_rcp_node_has_ownership = false;
00408     for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
00409       previous_rcp_node = itr->second.nodePtr;
00410       if (previous_rcp_node->has_ownership()) {
00411         previous_rcp_node_has_ownership = true;
00412         break;
00413       }
00414     }
00415     TEST_FOR_EXCEPTION(
00416       rcp_node_already_exists && rcp_node->has_ownership() && previous_rcp_node_has_ownership,
00417       DuplicateOwningRCPError,
00418       "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n"
00419       "RCPNode object to an existing managed object in another RCPNode:\n"
00420       "\n"
00421       "  New " << convertRCPNodeToString(rcp_node) << "\n"
00422       "\n"
00423       "  Existing " << convertRCPNodeToString(previous_rcp_node) << "\n"
00424       "\n"
00425       "  Number current nodes = " << rcp_node_list()->size() << "\n"
00426       "\n"
00427       "This may indicate that the user might be trying to create a weak RCP to an existing\n"
00428       "object but forgot make it non-ownning.  Perhaps they meant to use rcpFromRef(...)\n"
00429       "or an equivalent function?\n"
00430       "\n"
00431       << getCommonDebugNotesString();
00432       );
00433 
00434     // NOTE: We allow duplicate RCPNodes if the new node is non-owning.  This
00435     // might indicate a advanced usage of the RCP class that we want to
00436     // support.  The typical problem is when the programmer unknowingly
00437     // creates an owning RCP to an object already owned by another RCPNode.
00438 
00439     // Add the new RCP node keyed as described above.
00440     (*rcp_node_list()).insert(
00441       itr_itr.second,
00442       std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
00443       );
00444     // NOTE: Above, if there is already an existing RCPNode with the same key
00445     // value, this iterator itr_itr.second will point to one after the found
00446     // range.  I suspect that this might also ensure that the elements are
00447     // sorted in natural order.
00448 
00449     // Update the insertion number an node tracing statistics
00450     ++insertionNumber;
00451     ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
00452     loc_rcpNodeStatistics().maxNumRCPNodes =
00453       TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes());
00454   }
00455 }
00456 
00457 
00458 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
00459   TEST_FOR_EXCEPTION((CONDITION), \
00460     std::logic_error, \
00461     "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \
00462     << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \
00463     " active RCP nodes being traced even though all nodes should be traced." \
00464     "  This should not be possible and can only be an internal programming error!")
00465 
00466 
00467 void RCPNodeTracer::removeRCPNode( RCPNode* rcp_node )
00468 {
00469 
00470   // Here, we will try to remove an RCPNode reguardless if whether
00471   // loc_isTracingActiveRCPNodes==true or not.  This will not be a performance
00472   // problem and it will ensure that any RCPNode objects that are added to
00473   // this list will be removed and will not look like a memory leak.  In
00474   // non-debug mode, this function will never be called.  In debug mode, with
00475   // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
00476   // therefore this find(...) operation should be pretty cheap (even for a bad
00477   // implementation of std::map).
00478 
00479   TEUCHOS_ASSERT(rcp_node_list());
00480   typedef rcp_node_list_t::iterator itr_t;
00481   typedef std::pair<itr_t, itr_t> itr_itr_t;
00482 
00483   const itr_itr_t itr_itr =
00484     rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node));
00485   const bool rcp_node_exists = itr_itr.first != itr_itr.second;
00486 
00487 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
00488   // If we have the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned on a
00489   // compile time, then all RCPNode objects that get created will have been
00490   // added to this list.  In this case, we can asset that the node exists.
00491   TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
00492 #else
00493   // If the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned off, then is is
00494   // possible that an RCP got created before the bool
00495   // loc_isTracingActiveRCPNodes was turned on.  In this case, we must allow
00496   // for an RCP node not to have been added to this list.  In this case we
00497   // will just let this go!
00498 #endif
00499 
00500   if (rcp_node_exists) {
00501 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
00502     std::cerr
00503       << "RCPNodeTracer::removeRCPNode(...): Removing "
00504       << convertRCPNodeToString(rcp_node) << " ...\n";
00505 #endif
00506     bool foundRCPNode = false;
00507     for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
00508       if (itr->second.nodePtr == rcp_node) {
00509         rcp_node_list()->erase(itr);
00510         ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions;
00511         foundRCPNode = true;
00512         break;
00513       }
00514     }
00515     // Whoops! Did not find the node!
00516     TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
00517   }
00518 
00519 }
00520 
00521 
00522 RCPNode* RCPNodeTracer::getExistingRCPNodeGivenLookupKey(const void* p)
00523 {
00524   typedef rcp_node_list_t::iterator itr_t;
00525   typedef std::pair<itr_t, itr_t> itr_itr_t;
00526   if (!p)
00527     return 0;
00528   const itr_itr_t itr_itr = rcp_node_list()->equal_range(p);
00529   for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
00530     RCPNode* rcpNode = itr->second.nodePtr;
00531     if (rcpNode->has_ownership()) {
00532       return rcpNode;
00533     }
00534   }
00535   return 0;
00536   // NOTE: Above, we return the first RCPNode added that has the given key
00537   // value.  
00538 }
00539 
00540 
00541 std::string RCPNodeTracer::getActiveRCPNodeHeaderString()
00542 {
00543   return std::string(
00544     "\n***"
00545     "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
00546     "\n*** not been destroyed yet.  A memory checking tool may complain that these"
00547     "\n*** objects are not destroyed correctly."
00548     "\n***"
00549     "\n*** There can be many possible reasons that this might occur including:"
00550     "\n***"
00551     "\n***   a) The program called abort() or exit() before main() was finished."
00552     "\n***      All of the objects that would have been freed through destructors"
00553     "\n***      are not freed but some compilers (e.g. GCC) will still call the"
00554     "\n***      destructors on static objects (which is what causes this message"
00555     "\n***      to be printed)."
00556     "\n***"
00557     "\n***   b) The program is using raw new/delete to manage some objects and"
00558     "\n***      delete was not called correctly and the objects not deleted hold"
00559     "\n***      other objects through reference-counted pointers."
00560     "\n***"
00561     "\n***   c) This may be an indication that these objects may be involved in"
00562     "\n***      a circular dependency of reference-counted managed objects."
00563     "\n***\n"
00564     );
00565 }
00566 
00567 
00568 std::string RCPNodeTracer::getCommonDebugNotesString()
00569 {
00570   return std::string(
00571     "NOTE: To debug issues, open a debugger, and set a break point in the function where\n"
00572     "the RCPNode object is first created to determine the context where the object first\n"
00573     "gets created.  Each RCPNode object is given a unique insertionNumber to allow setting\n"
00574     "breakpoints in the code.  For example, in GDB one can perform:\n"
00575     "\n"
00576     "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
00577     "\n"
00578     "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n"
00579     "inserted.  In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n"
00580     "\n"
00581     "  (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] [ENTER]\n"
00582     "  (gdb) cond 1 insertionNumber==3 [ENTER]\n"
00583     "\n"
00584     "3) Run the program in the debugger.  In GDB, do:\n"
00585     "\n"
00586     "  (gdb) run [ENTER]\n"
00587     "\n"
00588     "4) Examine the call stack when the prgoram breaks in the function addNewRCPNode(...)\n"
00589     );
00590 }
00591 
00592 
00593 //
00594 // ActiveRCPNodesSetup
00595 //
00596 
00597 
00598 ActiveRCPNodesSetup::ActiveRCPNodesSetup()
00599 {
00600 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00601   std::cerr << "\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ << "\n";
00602 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00603   if (!rcp_node_list())
00604     rcp_node_list() = new rcp_node_list_t;
00605   ++count_;
00606 }
00607 
00608 
00609 ActiveRCPNodesSetup::~ActiveRCPNodesSetup()
00610 {
00611 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00612   std::cerr << "\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ << "\n";
00613 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00614   if( --count_ == 0 ) {
00615 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00616     std::cerr << "\nPrint active nodes!\n";
00617 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00618     std::cout << std::flush;
00619     TEST_FOR_EXCEPT(0==rcp_node_list());
00620     RCPNodeTracer::RCPNodeStatistics rcpNodeStatistics =
00621       RCPNodeTracer::getRCPNodeStatistics();
00622     if (rcpNodeStatistics.maxNumRCPNodes
00623       && RCPNodeTracer::getPrintRCPNodeStatisticsOnExit())
00624     {
00625       RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout);
00626     }
00627     RCPNodeTracer::printActiveRCPNodes(std::cerr);
00628     delete rcp_node_list();
00629     rcp_node_list() = 0;
00630   }
00631 }
00632 
00633 
00634 void Teuchos::ActiveRCPNodesSetup::foo()
00635 {
00636   int dummy = count_;
00637   ++dummy; // Avoid unused variable warning (bug 2664)
00638 }
00639 
00640 
00641 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
00642 
00643 
00644 //
00645 // RCPNodeHandle
00646 //
00647 
00648 
00649 void RCPNodeHandle::unbindOne()
00650 {
00651   if (node_) {
00652     // NOTE: We only deincrement the reference count after
00653     // we have called delete on the underlying object since
00654     // that call to delete may actually thrown an exception!
00655     if (node_->strong_count()==1 && strength()==RCP_STRONG) {
00656       // Delete the object (which might throw)
00657       node_->delete_obj();
00658  #ifdef TEUCHOS_DEBUG
00659       // We actaully also need to remove the RCPNode from the active list for
00660       // some specialized use cases that need to be able to create a new RCP
00661       // node pointing to the same memory.  What this means is that when the
00662       // strong count goes to zero and the referenced object is destroyed,
00663       // then it will not longer be picked up by any other code and instead it
00664       // will only be known by its remaining weak RCPNodeHandle objects in
00665       // order to perform debug-mode runtime checking in case a client tries
00666       // to access the obejct.
00667       local_activeRCPNodesSetup.foo(); // Make sure created!
00668       RCPNodeTracer::removeRCPNode(node_);
00669 #endif
00670    }
00671     // If we get here, no exception was thrown!
00672     if ( (node_->strong_count() + node_->weak_count()) == 1 ) {
00673       // The last RCP object is going away so time to delete
00674       // the entire node!
00675       delete node_;
00676       node_ = 0;
00677       // NOTE: No need to deincrement the reference count since this is
00678       // the last RCP object being deleted!
00679     }
00680     else {
00681       // The last RCP has not gone away so just deincrement the reference
00682       // count.
00683       node_->deincr_count(strength());
00684     }
00685   }
00686 }
00687 
00688 
00689 } // namespace Teuchos
00690 
00691 
00692 //
00693 // Non-member helpers
00694 //
00695 
00696 
00697 void Teuchos::throw_null_ptr_error( const std::string &type_name )
00698 {
00699   TEST_FOR_EXCEPTION(
00700     true, NullReferenceError, 
00701     type_name << " : You can not call operator->() or operator*()"
00702     <<" if getRawPtr()==0!" );
00703 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Wed Apr 13 09:57:30 2011 for Teuchos Package Browser (Single Doxygen Collection) by  doxygen 1.6.3