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