Teuchos - Trilinos Tools Package  Version of the Day
Teuchos_RCPNode.cpp
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #include "Teuchos_RCPNode.hpp"
43 #include "Teuchos_Assert.hpp"
44 #include "Teuchos_Exceptions.hpp"
45 
46 
47 // Defined this to see tracing of RCPNodes created and destroyed
48 //#define RCP_NODE_DEBUG_TRACE_PRINT
49 
50 
51 //
52 // Internal implementatation stuff
53 //
54 
55 
56 namespace {
57 
58 
59 //
60 // Local implementation types
61 //
62 
63 
64 struct RCPNodeInfo {
65  RCPNodeInfo() : nodePtr(0) {}
66  RCPNodeInfo(const std::string &info_in, Teuchos::RCPNode* nodePtr_in)
67  : info(info_in), nodePtr(nodePtr_in)
68  {}
69  std::string info;
70  Teuchos::RCPNode* nodePtr;
71 };
72 
73 
74 typedef std::pair<const void*, RCPNodeInfo> VoidPtrNodeRCPInfoPair_t;
75 
76 
77 typedef std::multimap<const void*, RCPNodeInfo> rcp_node_list_t;
78 
79 
80 class RCPNodeInfoListPred {
81 public:
82  bool operator()(const rcp_node_list_t::value_type &v1,
83  const rcp_node_list_t::value_type &v2
84  ) const
85  {
86 #ifdef TEUCHOS_DEBUG
87  return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number();
88 #else
89  return v1.first < v2.first;
90 #endif
91  }
92 };
93 
94 
95 //
96 // Local static functions returning references to local static objects to
97 // ensure objects are initilaized.
98 //
99 // Technically speaking, the static functions on RCPNodeTracer that use this
100 // data might be called from other translation units in pre-main code before
101 // this translation unit gets initialized. By using functions returning
102 // references to local static variable trick, we ensure that these objects are
103 // always initialized before they are used, no matter what.
104 //
105 // These could have been static functions on RCPNodeTracer but the advantage
106 // of defining these functions this way is that you can add and remove
107 // functions without affecting the *.hpp file and therefore avoid
108 // recompilation (and even relinking with shared libraries).
109 //
110 
111 
112 rcp_node_list_t*& rcp_node_list()
113 {
114  static rcp_node_list_t *s_rcp_node_list = 0;
115  // Here we must let the ActiveRCPNodesSetup constructor and destructor handle
116  // the creation and destruction of this map object. This will ensure that
117  // this map object will be valid when any global/static RCP objects are
118  // destroyed! Note that this object will get created and destroyed
119  // reguardless if whether we are tracing RCPNodes or not. This just makes our
120  // life simpler. NOTE: This list will always get allocated no mater if
121  // TEUCHOS_DEBUG is defined or node traceing is enabled or not.
122  return s_rcp_node_list;
123 }
124 
125 
126 bool& loc_isTracingActiveRCPNodes()
127 {
128  static bool s_loc_isTracingActiveRCPNodes =
129 #if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
130  true
131 #else
132  false
133 #endif
134  ;
135  return s_loc_isTracingActiveRCPNodes;
136 }
137 
138 
139 Teuchos::RCPNodeTracer::RCPNodeStatistics& loc_rcpNodeStatistics()
140 {
141  static Teuchos::RCPNodeTracer::RCPNodeStatistics s_loc_rcpNodeStatistics;
142  return s_loc_rcpNodeStatistics;
143 }
144 
145 
146 bool& loc_printRCPNodeStatisticsOnExit()
147 {
148  static bool s_loc_printRCPNodeStatisticsOnExit = false;
149  return s_loc_printRCPNodeStatisticsOnExit;
150 }
151 
152 
153 bool& loc_printActiveRcpNodesOnExit()
154 {
155  static bool s_loc_printActiveRcpNodesOnExit = true;
156  return s_loc_printActiveRcpNodesOnExit;
157 }
158 
159 
160 //
161 // Other helper functions
162 //
163 
164 // This function returns the const void* value that is used as the key to look
165 // up an RCPNode object that has been stored. If the RCPNode is holding a
166 // non-null reference, then we use that object address as the key. That way,
167 // we can detect if a user trys to create a new owning RCPNode to the same
168 // object. If the RCPNode has an null internal object pointer, then we will
169 // use the RCPNode's address itself. In this case, we want to check and see
170 // that all RCPNodes that get created get destroyed correctly.
171 const void* get_map_key_void_ptr(const Teuchos::RCPNode* rcp_node)
172 {
173  TEUCHOS_ASSERT(rcp_node);
174 #ifdef TEUCHOS_DEBUG
175  const void* base_obj_map_key_void_ptr = rcp_node->get_base_obj_map_key_void_ptr();
176  if (base_obj_map_key_void_ptr)
177  return base_obj_map_key_void_ptr;
178 #endif
179  return rcp_node;
180 }
181 
182 
183 std::string convertRCPNodeToString(const Teuchos::RCPNode* rcp_node)
184 {
185  std::ostringstream oss;
186  oss
187  << "RCPNode {address="
188  << rcp_node
189 #ifdef TEUCHOS_DEBUG
190  << ", base_obj_map_key_void_ptr=" << rcp_node->get_base_obj_map_key_void_ptr()
191 #endif
192  << ", base_obj_type_name=" << rcp_node->get_base_obj_type_name()
193  << ", map_key_void_ptr=" << get_map_key_void_ptr(rcp_node)
194  << ", has_ownership=" << rcp_node->has_ownership()
195 #ifdef TEUCHOS_DEBUG
196  << ", insertionNumber="<< rcp_node->insertion_number()
197 #endif
198  << "}";
199  return oss.str();
200 }
201 
202 
203 } // namespace
204 
205 
206 namespace Teuchos {
207 
208 
209 //
210 // RCPNode
211 //
212 
213 
214 void RCPNode::set_extra_data(
215  const any &extra_data, const std::string& name
216  ,EPrePostDestruction destroy_when
217  ,bool force_unique
218  )
219 {
220  if(extra_data_map_==NULL) {
221  extra_data_map_ = new extra_data_map_t;
222  }
223  const std::string type_and_name( extra_data.typeName() + std::string(":") + name );
224  extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
225 #ifdef TEUCHOS_DEBUG
227  (itr != extra_data_map_->end() && force_unique), std::invalid_argument
228  ,"Error, the type:name pair \'" << type_and_name
229  << "\' already exists and force_unique==true!" );
230 #endif
231  if (itr != extra_data_map_->end()) {
232  // Change existing extra data
233  itr->second = extra_data_entry_t(extra_data,destroy_when);
234  }
235  else {
236  // Insert new extra data
237  (*extra_data_map_)[type_and_name] =
238  extra_data_entry_t(extra_data,destroy_when);
239  }
240 }
241 
242 
243 any& RCPNode::get_extra_data( const std::string& type_name, const std::string& name )
244 {
245 #ifdef TEUCHOS_DEBUG
247  extra_data_map_==NULL, std::invalid_argument
248  ,"Error, no extra data has been set yet!" );
249 #endif
250  any *extra_data = get_optional_extra_data(type_name,name);
251 #ifdef TEUCHOS_DEBUG
252  if (!extra_data) {
253  const std::string type_and_name( type_name + std::string(":") + name );
255  extra_data == NULL, std::invalid_argument
256  ,"Error, the type:name pair \'" << type_and_name << "\' is not found!" );
257  }
258 #endif
259  return *extra_data;
260 }
261 
262 
263 any* RCPNode::get_optional_extra_data( const std::string& type_name,
264  const std::string& name )
265 {
266  if( extra_data_map_ == NULL ) return NULL;
267  const std::string type_and_name( type_name + std::string(":") + name );
268  extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
269  if(itr != extra_data_map_->end())
270  return &(*itr).second.extra_data;
271  return NULL;
272 }
273 
274 
275 void RCPNode::impl_pre_delete_extra_data()
276 {
277  for(
278  extra_data_map_t::iterator itr = extra_data_map_->begin();
279  itr != extra_data_map_->end();
280  ++itr
281  )
282  {
283  extra_data_map_t::value_type &entry = *itr;
284  if(entry.second.destroy_when == PRE_DESTROY)
285  entry.second.extra_data = any();
286  }
287 }
288 
289 
290 //
291 // RCPNodeTracer
292 //
293 
294 
295 // General user functions
296 
297 
298 bool RCPNodeTracer::isTracingActiveRCPNodes()
299 {
300  return loc_isTracingActiveRCPNodes();
301 }
302 
303 
304 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
305 void RCPNodeTracer::setTracingActiveRCPNodes(bool tracingActiveNodes)
306 {
307  loc_isTracingActiveRCPNodes() = tracingActiveNodes;
308 }
309 #endif
310 
311 
312 int RCPNodeTracer::numActiveRCPNodes()
313 {
314  // This list always exists, no matter debug or not so just access it.
315  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
316  return rcp_node_list()->size();
317 }
318 
319 
321 RCPNodeTracer::getRCPNodeStatistics()
322 {
323  return loc_rcpNodeStatistics();
324 }
325 
326 void RCPNodeTracer::printRCPNodeStatistics(
327  const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out)
328 {
329  out
330  << "\n***"
331  << "\n*** RCPNode Tracing statistics:"
332  << "\n**\n"
333  << "\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
334  << "\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
335  << "\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
336  << "\n";
337 }
338 
339 
340 void RCPNodeTracer::setPrintRCPNodeStatisticsOnExit(
341  bool printRCPNodeStatisticsOnExit)
342 {
343  loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
344 }
345 
346 
347 bool RCPNodeTracer::getPrintRCPNodeStatisticsOnExit()
348 {
349  return loc_printRCPNodeStatisticsOnExit();
350 }
351 
352 
353 void RCPNodeTracer::setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit)
354 {
355  loc_printActiveRcpNodesOnExit() = printActiveRcpNodesOnExit;
356 }
357 
358 
359 bool RCPNodeTracer::getPrintActiveRcpNodesOnExit()
360 {
361  return loc_printActiveRcpNodesOnExit();
362 }
363 
364 
365 void RCPNodeTracer::printActiveRCPNodes(std::ostream &out)
366 {
367 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
368  out
369  << "\nCalled printActiveRCPNodes() :"
370  << " rcp_node_list.size() = " << rcp_node_list().size() << "\n";
371 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
372  if (loc_isTracingActiveRCPNodes()) {
373  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
374  if (rcp_node_list()->size() > 0) {
375  out << getActiveRCPNodeHeaderString();
376  // Create a sorted-by-insertionNumber list
377  // NOTE: You have to use std::vector and *not* Teuchos::Array rcp here
378  // because this called at the very end and uses RCPNode itself in a
379  // debug-mode build.
380  typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t;
381  rcp_node_vec_t rcp_node_vec(rcp_node_list()->begin(), rcp_node_list()->end());
382  std::sort(rcp_node_vec.begin(), rcp_node_vec.end(), RCPNodeInfoListPred());
383  // Print the RCPNode objects sorted by insertion number
384  typedef rcp_node_vec_t::const_iterator itr_t;
385  int i = 0;
386  for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) {
387  const rcp_node_list_t::value_type &entry = *itr;
388  TEUCHOS_ASSERT(entry.second.nodePtr);
389  out
390  << "\n"
391  << std::setw(3) << std::right << i << std::left
392  << ": RCPNode (map_key_void_ptr=" << entry.first << ")\n"
393  << " Information = " << entry.second.info << "\n"
394  << " RCPNode address = " << entry.second.nodePtr << "\n"
395 #ifdef TEUCHOS_DEBUG
396  << " insertionNumber = " << entry.second.nodePtr->insertion_number()
397 #endif
398  ;
399  ++i;
400  }
401  out << "\n\n"
402  << getCommonDebugNotesString();
403  }
404  }
405 }
406 
407 
408 // Internal implementation functions
409 
410 
411 void RCPNodeTracer::addNewRCPNode( RCPNode* rcp_node, const std::string &info )
412 {
413 
414  // Used to allow unique identification of rcp_node to allow setting breakpoints
415  static int insertionNumber = 0;
416 
417  // Set the insertion number right away in case an exception gets thrown so
418  // that you can set a break point to debug this.
419 #ifdef TEUCHOS_DEBUG
420  rcp_node->set_insertion_number(insertionNumber);
421 #endif
422 
423  if (loc_isTracingActiveRCPNodes()) {
424 
425  // Print the node we are adding if configured to do so. We have to send
426  // to std::cerr to make sure that this gets printed.
427 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
428  std::cerr
429  << "RCPNodeTracer::addNewRCPNode(...): Adding "
430  << convertRCPNodeToString(rcp_node) << " ...\n";
431 #endif
432 
433  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
434 
435  const void * const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
436 
437  // See if the rcp_node or its object has already been added.
438  typedef rcp_node_list_t::iterator itr_t;
439  typedef std::pair<itr_t, itr_t> itr_itr_t;
440  const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr);
441  const bool rcp_node_already_exists = itr_itr.first != itr_itr.second;
442  RCPNode *previous_rcp_node = 0;
443  bool previous_rcp_node_has_ownership = false;
444  for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
445  previous_rcp_node = itr->second.nodePtr;
446  if (previous_rcp_node->has_ownership()) {
447  previous_rcp_node_has_ownership = true;
448  break;
449  }
450  }
452  rcp_node_already_exists && rcp_node->has_ownership() && previous_rcp_node_has_ownership,
454  "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n"
455  "RCPNode object to an existing managed object in another RCPNode:\n"
456  "\n"
457  " New " << convertRCPNodeToString(rcp_node) << "\n"
458  "\n"
459  " Existing " << convertRCPNodeToString(previous_rcp_node) << "\n"
460  "\n"
461  " Number current nodes = " << rcp_node_list()->size() << "\n"
462  "\n"
463  "This may indicate that the user might be trying to create a weak RCP to an existing\n"
464  "object but forgot make it non-ownning. Perhaps they meant to use rcpFromRef(...)\n"
465  "or an equivalent function?\n"
466  "\n"
467  << getCommonDebugNotesString();
468  );
469 
470  // NOTE: We allow duplicate RCPNodes if the new node is non-owning. This
471  // might indicate a advanced usage of the RCP class that we want to
472  // support. The typical problem is when the programmer unknowingly
473  // creates an owning RCP to an object already owned by another RCPNode.
474 
475  // Add the new RCP node keyed as described above.
476  (*rcp_node_list()).insert(
477  itr_itr.second,
478  std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
479  );
480  // NOTE: Above, if there is already an existing RCPNode with the same key
481  // value, this iterator itr_itr.second will point to one after the found
482  // range. I suspect that this might also ensure that the elements are
483  // sorted in natural order.
484 
485  // Update the insertion number an node tracing statistics
486  ++insertionNumber;
487  ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
488  loc_rcpNodeStatistics().maxNumRCPNodes =
489  TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes());
490  }
491 }
492 
493 
494 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
495  TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \
496  std::logic_error, \
497  "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \
498  << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \
499  " active RCP nodes being traced even though all nodes should be traced." \
500  " This should not be possible and can only be an internal programming error!")
501 
502 
503 void RCPNodeTracer::removeRCPNode( RCPNode* rcp_node )
504 {
505 
506  // Here, we will try to remove an RCPNode reguardless if whether
507  // loc_isTracingActiveRCPNodes==true or not. This will not be a performance
508  // problem and it will ensure that any RCPNode objects that are added to
509  // this list will be removed and will not look like a memory leak. In
510  // non-debug mode, this function will never be called. In debug mode, with
511  // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
512  // therefore this find(...) operation should be pretty cheap (even for a bad
513  // implementation of std::map).
514 
515  TEUCHOS_ASSERT(rcp_node_list());
516  typedef rcp_node_list_t::iterator itr_t;
517  typedef std::pair<itr_t, itr_t> itr_itr_t;
518 
519  const itr_itr_t itr_itr =
520  rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node));
521  const bool rcp_node_exists = itr_itr.first != itr_itr.second;
522 
523 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
524  // If we have the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned on a
525  // compile time, then all RCPNode objects that get created will have been
526  // added to this list. In this case, we can asset that the node exists.
527  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
528 #else
529  // If the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned off, then is is
530  // possible that an RCP got created before the bool
531  // loc_isTracingActiveRCPNodes was turned on. In this case, we must allow
532  // for an RCP node not to have been added to this list. In this case we
533  // will just let this go!
534 #endif
535 
536  if (rcp_node_exists) {
537 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
538  std::cerr
539  << "RCPNodeTracer::removeRCPNode(...): Removing "
540  << convertRCPNodeToString(rcp_node) << " ...\n";
541 #endif
542  bool foundRCPNode = false;
543  for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
544  if (itr->second.nodePtr == rcp_node) {
545  rcp_node_list()->erase(itr);
546  ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions;
547  foundRCPNode = true;
548  break;
549  }
550  }
551  // Whoops! Did not find the node!
552  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
553  }
554 
555 }
556 
557 
558 RCPNode* RCPNodeTracer::getExistingRCPNodeGivenLookupKey(const void* p)
559 {
560  typedef rcp_node_list_t::iterator itr_t;
561  typedef std::pair<itr_t, itr_t> itr_itr_t;
562  if (!p)
563  return 0;
564  const itr_itr_t itr_itr = rcp_node_list()->equal_range(p);
565  for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
566  RCPNode* rcpNode = itr->second.nodePtr;
567  if (rcpNode->has_ownership()) {
568  return rcpNode;
569  }
570  }
571  return 0;
572  // NOTE: Above, we return the first RCPNode added that has the given key
573  // value.
574 }
575 
576 
577 std::string RCPNodeTracer::getActiveRCPNodeHeaderString()
578 {
579  return std::string(
580  "\n***"
581  "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
582  "\n*** not been destroyed yet. A memory checking tool may complain that these"
583  "\n*** objects are not destroyed correctly."
584  "\n***"
585  "\n*** There can be many possible reasons that this might occur including:"
586  "\n***"
587  "\n*** a) The program called abort() or exit() before main() was finished."
588  "\n*** All of the objects that would have been freed through destructors"
589  "\n*** are not freed but some compilers (e.g. GCC) will still call the"
590  "\n*** destructors on static objects (which is what causes this message"
591  "\n*** to be printed)."
592  "\n***"
593  "\n*** b) The program is using raw new/delete to manage some objects and"
594  "\n*** delete was not called correctly and the objects not deleted hold"
595  "\n*** other objects through reference-counted pointers."
596  "\n***"
597  "\n*** c) This may be an indication that these objects may be involved in"
598  "\n*** a circular dependency of reference-counted managed objects."
599  "\n***\n"
600  );
601 }
602 
603 
604 std::string RCPNodeTracer::getCommonDebugNotesString()
605 {
606  return std::string(
607  "NOTE: To debug issues, open a debugger, and set a break point in the function where\n"
608  "the RCPNode object is first created to determine the context where the object first\n"
609  "gets created. Each RCPNode object is given a unique insertionNumber to allow setting\n"
610  "breakpoints in the code. For example, in GDB one can perform:\n"
611  "\n"
612  "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
613  "\n"
614  "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n"
615  "inserted. In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n"
616  "\n"
617  " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n"
618  " (gdb) cond 1 insertionNumber==3 [ENTER]\n"
619  "\n"
620  "3) Run the program in the debugger. In GDB, do:\n"
621  "\n"
622  " (gdb) run [ENTER]\n"
623  "\n"
624  "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n"
625  );
626 }
627 
628 
629 //
630 // ActiveRCPNodesSetup
631 //
632 
633 
634 ActiveRCPNodesSetup::ActiveRCPNodesSetup()
635 {
636 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
637  std::cerr << "\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ << "\n";
638 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
639  if (!rcp_node_list())
640  rcp_node_list() = new rcp_node_list_t;
641  ++count_;
642 }
643 
644 
645 ActiveRCPNodesSetup::~ActiveRCPNodesSetup()
646 {
647 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
648  std::cerr << "\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ << "\n";
649 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
650  if( --count_ == 0 ) {
651 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
652  std::cerr << "\nPrint active nodes!\n";
653 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
654  std::cout << std::flush;
655  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
656  RCPNodeTracer::RCPNodeStatistics rcpNodeStatistics =
657  RCPNodeTracer::getRCPNodeStatistics();
658  if (rcpNodeStatistics.maxNumRCPNodes
659  && RCPNodeTracer::getPrintRCPNodeStatisticsOnExit())
660  {
661  RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout);
662  }
663  if (RCPNodeTracer::getPrintActiveRcpNodesOnExit()) {
664  RCPNodeTracer::printActiveRCPNodes(std::cerr);
665  }
666  delete rcp_node_list();
667  rcp_node_list() = 0;
668  }
669 }
670 
671 
673 {
674  int dummy = count_;
675  ++dummy; // Avoid unused variable warning (bug 2664)
676 }
677 
678 
679 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
680 
681 
682 //
683 // RCPNodeHandle
684 //
685 
686 
687 void RCPNodeHandle::unbindOne()
688 {
689  if (node_) {
690  // NOTE: We only deincrement the reference count after
691  // we have called delete on the underlying object since
692  // that call to delete may actually thrown an exception!
693  if (node_->strong_count()==1 && strength()==RCP_STRONG) {
694  // Delete the object (which might throw)
695  node_->delete_obj();
696  #ifdef TEUCHOS_DEBUG
697  // We actaully also need to remove the RCPNode from the active list for
698  // some specialized use cases that need to be able to create a new RCP
699  // node pointing to the same memory. What this means is that when the
700  // strong count goes to zero and the referenced object is destroyed,
701  // then it will not longer be picked up by any other code and instead it
702  // will only be known by its remaining weak RCPNodeHandle objects in
703  // order to perform debug-mode runtime checking in case a client tries
704  // to access the obejct.
705  local_activeRCPNodesSetup.foo(); // Make sure created!
706  RCPNodeTracer::removeRCPNode(node_);
707 #endif
708  }
709  // If we get here, no exception was thrown!
710  if ( (node_->strong_count() + node_->weak_count()) == 1 ) {
711  // The last RCP object is going away so time to delete
712  // the entire node!
713  delete node_;
714  node_ = 0;
715  // NOTE: No need to deincrement the reference count since this is
716  // the last RCP object being deleted!
717  }
718  else {
719  // The last RCP has not gone away so just deincrement the reference
720  // count.
721  node_->deincr_count(strength());
722  }
723  }
724 }
725 
726 
727 } // namespace Teuchos
728 
729 
730 //
731 // Non-member helpers
732 //
733 
734 
735 void Teuchos::throw_null_ptr_error( const std::string &type_name )
736 {
738  true, NullReferenceError,
739  type_name << " : You can not call operator->() or operator*()"
740  <<" if getRawPtr()==0!" );
741 }
Null reference error exception class.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Modified boost::any class, which is a container for a templated value.
Definition: Teuchos_any.hpp:86
void has_ownership(bool has_ownership_in)
Node class to keep track of address and the reference count for a reference-counted utility class and...
virtual const std::string get_base_obj_type_name() const =0
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos, as well as a number of utility routines.
std::string typeName() const
Return the name of the type.
EPrePostDestruction
Used to specify a pre or post destruction of extra data.
#define TEUCHOS_ASSERT(assertion_test)
This macro is throws when an assert fails.
Reference-counted pointer node classes.
Thrown if a duplicate owning RCP is creatd the the same object.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
This macro is designed to be a short version of TEUCHOS_TEST_FOR_EXCEPTION() that is easier to call...