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  return 0;
318 }
319 
320 
322 RCPNodeTracer::getRCPNodeStatistics()
323 {
324  return loc_rcpNodeStatistics();
325 }
326 
327 void RCPNodeTracer::printRCPNodeStatistics(
328  const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out)
329 {
330  out
331  << "\n***"
332  << "\n*** RCPNode Tracing statistics:"
333  << "\n**\n"
334  << "\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
335  << "\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
336  << "\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
337  << "\n";
338 }
339 
340 
341 void RCPNodeTracer::setPrintRCPNodeStatisticsOnExit(
342  bool printRCPNodeStatisticsOnExit)
343 {
344  loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
345 }
346 
347 
348 bool RCPNodeTracer::getPrintRCPNodeStatisticsOnExit()
349 {
350  return loc_printRCPNodeStatisticsOnExit();
351 }
352 
353 
354 void RCPNodeTracer::setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit)
355 {
356  loc_printActiveRcpNodesOnExit() = printActiveRcpNodesOnExit;
357 }
358 
359 
360 bool RCPNodeTracer::getPrintActiveRcpNodesOnExit()
361 {
362  return loc_printActiveRcpNodesOnExit();
363 }
364 
365 
366 void RCPNodeTracer::printActiveRCPNodes(std::ostream &out)
367 {
368 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
369  out
370  << "\nCalled printActiveRCPNodes() :"
371  << " rcp_node_list.size() = " << rcp_node_list().size() << "\n";
372 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
373  if (loc_isTracingActiveRCPNodes()) {
374  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
375  if (rcp_node_list()->size() > 0) {
376  out << getActiveRCPNodeHeaderString();
377  // Create a sorted-by-insertionNumber list
378  // NOTE: You have to use std::vector and *not* Teuchos::Array rcp here
379  // because this called at the very end and uses RCPNode itself in a
380  // debug-mode build.
381  typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t;
382  rcp_node_vec_t rcp_node_vec(rcp_node_list()->begin(), rcp_node_list()->end());
383  std::sort(rcp_node_vec.begin(), rcp_node_vec.end(), RCPNodeInfoListPred());
384  // Print the RCPNode objects sorted by insertion number
385  typedef rcp_node_vec_t::const_iterator itr_t;
386  int i = 0;
387  for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) {
388  const rcp_node_list_t::value_type &entry = *itr;
389  TEUCHOS_ASSERT(entry.second.nodePtr);
390  out
391  << "\n"
392  << std::setw(3) << std::right << i << std::left
393  << ": RCPNode (map_key_void_ptr=" << entry.first << ")\n"
394  << " Information = " << entry.second.info << "\n"
395  << " RCPNode address = " << entry.second.nodePtr << "\n"
396 #ifdef TEUCHOS_DEBUG
397  << " insertionNumber = " << entry.second.nodePtr->insertion_number()
398 #endif
399  ;
400  ++i;
401  }
402  out << "\n\n"
403  << getCommonDebugNotesString();
404  }
405  }
406 }
407 
408 
409 // Internal implementation functions
410 
411 
412 void RCPNodeTracer::addNewRCPNode( RCPNode* rcp_node, const std::string &info )
413 {
414 
415  // Used to allow unique identification of rcp_node to allow setting breakpoints
416  static int insertionNumber = 0;
417 
418  // Set the insertion number right away in case an exception gets thrown so
419  // that you can set a break point to debug this.
420 #ifdef TEUCHOS_DEBUG
421  rcp_node->set_insertion_number(insertionNumber);
422 #endif
423 
424  if (loc_isTracingActiveRCPNodes()) {
425 
426  // Print the node we are adding if configured to do so. We have to send
427  // to std::cerr to make sure that this gets printed.
428 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
429  std::cerr
430  << "RCPNodeTracer::addNewRCPNode(...): Adding "
431  << convertRCPNodeToString(rcp_node) << " ...\n";
432 #endif
433 
434  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
435 
436  const void * const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
437 
438  // See if the rcp_node or its object has already been added.
439  typedef rcp_node_list_t::iterator itr_t;
440  typedef std::pair<itr_t, itr_t> itr_itr_t;
441  const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr);
442  const bool rcp_node_already_exists = itr_itr.first != itr_itr.second;
443  RCPNode *previous_rcp_node = 0;
444  bool previous_rcp_node_has_ownership = false;
445  for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
446  previous_rcp_node = itr->second.nodePtr;
447  if (previous_rcp_node->has_ownership()) {
448  previous_rcp_node_has_ownership = true;
449  break;
450  }
451  }
453  rcp_node_already_exists && rcp_node->has_ownership() && previous_rcp_node_has_ownership,
455  "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n"
456  "RCPNode object to an existing managed object in another RCPNode:\n"
457  "\n"
458  " New " << convertRCPNodeToString(rcp_node) << "\n"
459  "\n"
460  " Existing " << convertRCPNodeToString(previous_rcp_node) << "\n"
461  "\n"
462  " Number current nodes = " << rcp_node_list()->size() << "\n"
463  "\n"
464  "This may indicate that the user might be trying to create a weak RCP to an existing\n"
465  "object but forgot make it non-ownning. Perhaps they meant to use rcpFromRef(...)\n"
466  "or an equivalent function?\n"
467  "\n"
468  << getCommonDebugNotesString();
469  );
470 
471  // NOTE: We allow duplicate RCPNodes if the new node is non-owning. This
472  // might indicate a advanced usage of the RCP class that we want to
473  // support. The typical problem is when the programmer unknowingly
474  // creates an owning RCP to an object already owned by another RCPNode.
475 
476  // Add the new RCP node keyed as described above.
477  (*rcp_node_list()).insert(
478  itr_itr.second,
479  std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
480  );
481  // NOTE: Above, if there is already an existing RCPNode with the same key
482  // value, this iterator itr_itr.second will point to one after the found
483  // range. I suspect that this might also ensure that the elements are
484  // sorted in natural order.
485 
486  // Update the insertion number an node tracing statistics
487  ++insertionNumber;
488  ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
489  loc_rcpNodeStatistics().maxNumRCPNodes =
490  TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes());
491  }
492 }
493 
494 
495 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
496  TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \
497  std::logic_error, \
498  "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \
499  << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \
500  " active RCP nodes being traced even though all nodes should be traced." \
501  " This should not be possible and can only be an internal programming error!")
502 
503 
504 void RCPNodeTracer::removeRCPNode( RCPNode* rcp_node )
505 {
506 
507  // Here, we will try to remove an RCPNode reguardless if whether
508  // loc_isTracingActiveRCPNodes==true or not. This will not be a performance
509  // problem and it will ensure that any RCPNode objects that are added to
510  // this list will be removed and will not look like a memory leak. In
511  // non-debug mode, this function will never be called. In debug mode, with
512  // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
513  // therefore this find(...) operation should be pretty cheap (even for a bad
514  // implementation of std::map).
515 
516  TEUCHOS_ASSERT(rcp_node_list());
517  typedef rcp_node_list_t::iterator itr_t;
518  typedef std::pair<itr_t, itr_t> itr_itr_t;
519 
520  const itr_itr_t itr_itr =
521  rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node));
522  const bool rcp_node_exists = itr_itr.first != itr_itr.second;
523 
524 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
525  // If we have the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned on a
526  // compile time, then all RCPNode objects that get created will have been
527  // added to this list. In this case, we can asset that the node exists.
528  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
529 #else
530  // If the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned off, then is is
531  // possible that an RCP got created before the bool
532  // loc_isTracingActiveRCPNodes was turned on. In this case, we must allow
533  // for an RCP node not to have been added to this list. In this case we
534  // will just let this go!
535 #endif
536 
537  if (rcp_node_exists) {
538 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
539  std::cerr
540  << "RCPNodeTracer::removeRCPNode(...): Removing "
541  << convertRCPNodeToString(rcp_node) << " ...\n";
542 #endif
543  bool foundRCPNode = false;
544  for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
545  if (itr->second.nodePtr == rcp_node) {
546  rcp_node_list()->erase(itr);
547  ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions;
548  foundRCPNode = true;
549  break;
550  }
551  }
552  // Whoops! Did not find the node!
553  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
554  }
555 
556 }
557 
558 
559 RCPNode* RCPNodeTracer::getExistingRCPNodeGivenLookupKey(const void* p)
560 {
561  typedef rcp_node_list_t::iterator itr_t;
562  typedef std::pair<itr_t, itr_t> itr_itr_t;
563  if (!p)
564  return 0;
565  const itr_itr_t itr_itr = rcp_node_list()->equal_range(p);
566  for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
567  RCPNode* rcpNode = itr->second.nodePtr;
568  if (rcpNode->has_ownership()) {
569  return rcpNode;
570  }
571  }
572  return 0;
573  // NOTE: Above, we return the first RCPNode added that has the given key
574  // value.
575 }
576 
577 
578 std::string RCPNodeTracer::getActiveRCPNodeHeaderString()
579 {
580  return std::string(
581  "\n***"
582  "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
583  "\n*** not been destroyed yet. A memory checking tool may complain that these"
584  "\n*** objects are not destroyed correctly."
585  "\n***"
586  "\n*** There can be many possible reasons that this might occur including:"
587  "\n***"
588  "\n*** a) The program called abort() or exit() before main() was finished."
589  "\n*** All of the objects that would have been freed through destructors"
590  "\n*** are not freed but some compilers (e.g. GCC) will still call the"
591  "\n*** destructors on static objects (which is what causes this message"
592  "\n*** to be printed)."
593  "\n***"
594  "\n*** b) The program is using raw new/delete to manage some objects and"
595  "\n*** delete was not called correctly and the objects not deleted hold"
596  "\n*** other objects through reference-counted pointers."
597  "\n***"
598  "\n*** c) This may be an indication that these objects may be involved in"
599  "\n*** a circular dependency of reference-counted managed objects."
600  "\n***\n"
601  );
602 }
603 
604 
605 std::string RCPNodeTracer::getCommonDebugNotesString()
606 {
607  return std::string(
608  "NOTE: To debug issues, open a debugger, and set a break point in the function where\n"
609  "the RCPNode object is first created to determine the context where the object first\n"
610  "gets created. Each RCPNode object is given a unique insertionNumber to allow setting\n"
611  "breakpoints in the code. For example, in GDB one can perform:\n"
612  "\n"
613  "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
614  "\n"
615  "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n"
616  "inserted. In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n"
617  "\n"
618  " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n"
619  " (gdb) cond 1 insertionNumber==3 [ENTER]\n"
620  "\n"
621  "3) Run the program in the debugger. In GDB, do:\n"
622  "\n"
623  " (gdb) run [ENTER]\n"
624  "\n"
625  "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n"
626  );
627 }
628 
629 
630 //
631 // ActiveRCPNodesSetup
632 //
633 
634 
635 ActiveRCPNodesSetup::ActiveRCPNodesSetup()
636 {
637 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
638  std::cerr << "\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ << "\n";
639 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
640  if (!rcp_node_list())
641  rcp_node_list() = new rcp_node_list_t;
642  ++count_;
643 }
644 
645 
646 ActiveRCPNodesSetup::~ActiveRCPNodesSetup()
647 {
648 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
649  std::cerr << "\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ << "\n";
650 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
651  if( --count_ == 0 ) {
652 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
653  std::cerr << "\nPrint active nodes!\n";
654 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
655  std::cout << std::flush;
656  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
657  RCPNodeTracer::RCPNodeStatistics rcpNodeStatistics =
658  RCPNodeTracer::getRCPNodeStatistics();
659  if (rcpNodeStatistics.maxNumRCPNodes
660  && RCPNodeTracer::getPrintRCPNodeStatisticsOnExit())
661  {
662  RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout);
663  }
664  if (RCPNodeTracer::getPrintActiveRcpNodesOnExit()) {
665  RCPNodeTracer::printActiveRCPNodes(std::cerr);
666  }
667  delete rcp_node_list();
668  rcp_node_list() = 0;
669  }
670 }
671 
672 
674 {
675  int dummy = count_;
676  ++dummy; // Avoid unused variable warning (bug 2664)
677 }
678 
679 
680 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
681 
682 
683 //
684 // RCPNodeHandle
685 //
686 
687 
688 void RCPNodeHandle::unbindOne()
689 {
690  if (node_) {
691  // NOTE: We only deincrement the reference count after
692  // we have called delete on the underlying object since
693  // that call to delete may actually thrown an exception!
694  if (node_->strong_count()==1 && strength()==RCP_STRONG) {
695  // Delete the object (which might throw)
696  node_->delete_obj();
697  #ifdef TEUCHOS_DEBUG
698  // We actaully also need to remove the RCPNode from the active list for
699  // some specialized use cases that need to be able to create a new RCP
700  // node pointing to the same memory. What this means is that when the
701  // strong count goes to zero and the referenced object is destroyed,
702  // then it will not longer be picked up by any other code and instead it
703  // will only be known by its remaining weak RCPNodeHandle objects in
704  // order to perform debug-mode runtime checking in case a client tries
705  // to access the obejct.
706  local_activeRCPNodesSetup.foo(); // Make sure created!
707  RCPNodeTracer::removeRCPNode(node_);
708 #endif
709  }
710  // If we get here, no exception was thrown!
711  if ( (node_->strong_count() + node_->weak_count()) == 1 ) {
712  // The last RCP object is going away so time to delete
713  // the entire node!
714  delete node_;
715  node_ = 0;
716  // NOTE: No need to deincrement the reference count since this is
717  // the last RCP object being deleted!
718  }
719  else {
720  // The last RCP has not gone away so just deincrement the reference
721  // count.
722  node_->deincr_count(strength());
723  }
724  }
725 }
726 
727 
728 } // namespace Teuchos
729 
730 
731 //
732 // Non-member helpers
733 //
734 
735 
736 void Teuchos::throw_null_ptr_error( const std::string &type_name )
737 {
739  true, NullReferenceError,
740  type_name << " : You can not call operator->() or operator*()"
741  <<" if getRawPtr()==0!" );
742 }
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.
EPrePostDestruction
Used to specify a pre or post destruction of extra data.
std::string typeName() const
Return the name of the type.
#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...