|
Teuchos - Trilinos Tools Package Version of the Day
|
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 }
1.7.4