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 //
154 // Other helper functions
155 //
156 
157 // This function returns the const void* value that is used as the key to look
158 // up an RCPNode object that has been stored. If the RCPNode is holding a
159 // non-null reference, then we use that object address as the key. That way,
160 // we can detect if a user trys to create a new owning RCPNode to the same
161 // object. If the RCPNode has an null internal object pointer, then we will
162 // use the RCPNode's address itself. In this case, we want to check and see
163 // that all RCPNodes that get created get destroyed correctly.
164 const void* get_map_key_void_ptr(const Teuchos::RCPNode* rcp_node)
165 {
166  TEUCHOS_ASSERT(rcp_node);
167 #ifdef TEUCHOS_DEBUG
168  const void* base_obj_map_key_void_ptr = rcp_node->get_base_obj_map_key_void_ptr();
169  if (base_obj_map_key_void_ptr)
170  return base_obj_map_key_void_ptr;
171 #endif
172  return rcp_node;
173 }
174 
175 
176 std::string convertRCPNodeToString(const Teuchos::RCPNode* rcp_node)
177 {
178  std::ostringstream oss;
179  oss
180  << "RCPNode {address="
181  << rcp_node
182 #ifdef TEUCHOS_DEBUG
183  << ", base_obj_map_key_void_ptr=" << rcp_node->get_base_obj_map_key_void_ptr()
184 #endif
185  << ", base_obj_type_name=" << rcp_node->get_base_obj_type_name()
186  << ", map_key_void_ptr=" << get_map_key_void_ptr(rcp_node)
187  << ", has_ownership=" << rcp_node->has_ownership()
188 #ifdef TEUCHOS_DEBUG
189  << ", insertionNumber="<< rcp_node->insertion_number()
190 #endif
191  << "}";
192  return oss.str();
193 }
194 
195 
196 } // namespace
197 
198 
199 namespace Teuchos {
200 
201 
202 //
203 // RCPNode
204 //
205 
206 
207 void RCPNode::set_extra_data(
208  const any &extra_data, const std::string& name
209  ,EPrePostDestruction destroy_when
210  ,bool force_unique
211  )
212 {
213  if(extra_data_map_==NULL) {
214  extra_data_map_ = new extra_data_map_t;
215  }
216  const std::string type_and_name( extra_data.typeName() + std::string(":") + name );
217  extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
218 #ifdef TEUCHOS_DEBUG
220  (itr != extra_data_map_->end() && force_unique), std::invalid_argument
221  ,"Error, the type:name pair \'" << type_and_name
222  << "\' already exists and force_unique==true!" );
223 #endif
224  if (itr != extra_data_map_->end()) {
225  // Change existing extra data
226  itr->second = extra_data_entry_t(extra_data,destroy_when);
227  }
228  else {
229  // Insert new extra data
230  (*extra_data_map_)[type_and_name] =
231  extra_data_entry_t(extra_data,destroy_when);
232  }
233 }
234 
235 
236 any& RCPNode::get_extra_data( const std::string& type_name, const std::string& name )
237 {
238 #ifdef TEUCHOS_DEBUG
240  extra_data_map_==NULL, std::invalid_argument
241  ,"Error, no extra data has been set yet!" );
242 #endif
243  any *extra_data = get_optional_extra_data(type_name,name);
244 #ifdef TEUCHOS_DEBUG
245  if (!extra_data) {
246  const std::string type_and_name( type_name + std::string(":") + name );
248  extra_data == NULL, std::invalid_argument
249  ,"Error, the type:name pair \'" << type_and_name << "\' is not found!" );
250  }
251 #endif
252  return *extra_data;
253 }
254 
255 
256 any* RCPNode::get_optional_extra_data( const std::string& type_name,
257  const std::string& name )
258 {
259  if( extra_data_map_ == NULL ) return NULL;
260  const std::string type_and_name( type_name + std::string(":") + name );
261  extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
262  if(itr != extra_data_map_->end())
263  return &(*itr).second.extra_data;
264  return NULL;
265 }
266 
267 
268 void RCPNode::impl_pre_delete_extra_data()
269 {
270  for(
271  extra_data_map_t::iterator itr = extra_data_map_->begin();
272  itr != extra_data_map_->end();
273  ++itr
274  )
275  {
276  extra_data_map_t::value_type &entry = *itr;
277  if(entry.second.destroy_when == PRE_DESTROY)
278  entry.second.extra_data = any();
279  }
280 }
281 
282 
283 //
284 // RCPNodeTracer
285 //
286 
287 
288 // General user functions
289 
290 
291 bool RCPNodeTracer::isTracingActiveRCPNodes()
292 {
293  return loc_isTracingActiveRCPNodes();
294 }
295 
296 
297 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
298 void RCPNodeTracer::setTracingActiveRCPNodes(bool tracingActiveNodes)
299 {
300  loc_isTracingActiveRCPNodes() = tracingActiveNodes;
301 }
302 #endif
303 
304 
305 int RCPNodeTracer::numActiveRCPNodes()
306 {
307  // This list always exists, no matter debug or not so just access it.
308  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
309  return rcp_node_list()->size();
310  return 0;
311 }
312 
313 
315 RCPNodeTracer::getRCPNodeStatistics()
316 {
317  return loc_rcpNodeStatistics();
318 }
319 
320 void RCPNodeTracer::printRCPNodeStatistics(
321  const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out)
322 {
323  out
324  << "\n***"
325  << "\n*** RCPNode Tracing statistics:"
326  << "\n**\n"
327  << "\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
328  << "\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
329  << "\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
330  << "\n";
331 }
332 
333 
334 void RCPNodeTracer::setPrintRCPNodeStatisticsOnExit(
335  bool printRCPNodeStatisticsOnExit)
336 {
337  loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
338 }
339 
340 
341 bool RCPNodeTracer::getPrintRCPNodeStatisticsOnExit()
342 {
343  return loc_printRCPNodeStatisticsOnExit();
344 }
345 
346 
347 void RCPNodeTracer::printActiveRCPNodes(std::ostream &out)
348 {
349 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
350  out
351  << "\nCalled printActiveRCPNodes() :"
352  << " rcp_node_list.size() = " << rcp_node_list().size() << "\n";
353 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
354  if (loc_isTracingActiveRCPNodes()) {
355  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
356  if (rcp_node_list()->size() > 0) {
357  out << getActiveRCPNodeHeaderString();
358  // Create a sorted-by-insertionNumber list
359  // NOTE: You have to use std::vector and *not* Teuchos::Array rcp here
360  // because this called at the very end and uses RCPNode itself in a
361  // debug-mode build.
362  typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t;
363  rcp_node_vec_t rcp_node_vec(rcp_node_list()->begin(), rcp_node_list()->end());
364  std::sort(rcp_node_vec.begin(), rcp_node_vec.end(), RCPNodeInfoListPred());
365  // Print the RCPNode objects sorted by insertion number
366  typedef rcp_node_vec_t::const_iterator itr_t;
367  int i = 0;
368  for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) {
369  const rcp_node_list_t::value_type &entry = *itr;
370  TEUCHOS_ASSERT(entry.second.nodePtr);
371  out
372  << "\n"
373  << std::setw(3) << std::right << i << std::left
374  << ": RCPNode (map_key_void_ptr=" << entry.first << ")\n"
375  << " Information = " << entry.second.info << "\n"
376  << " RCPNode address = " << entry.second.nodePtr << "\n"
377 #ifdef TEUCHOS_DEBUG
378  << " insertionNumber = " << entry.second.nodePtr->insertion_number()
379 #endif
380  ;
381  ++i;
382  }
383  out << "\n\n"
384  << getCommonDebugNotesString();
385  }
386  }
387 }
388 
389 
390 // Internal implementation functions
391 
392 
393 void RCPNodeTracer::addNewRCPNode( RCPNode* rcp_node, const std::string &info )
394 {
395 
396  // Used to allow unique identification of rcp_node to allow setting breakpoints
397  static int insertionNumber = 0;
398 
399  // Set the insertion number right away in case an exception gets thrown so
400  // that you can set a break point to debug this.
401 #ifdef TEUCHOS_DEBUG
402  rcp_node->set_insertion_number(insertionNumber);
403 #endif
404 
405  if (loc_isTracingActiveRCPNodes()) {
406 
407  // Print the node we are adding if configured to do so. We have to send
408  // to std::cerr to make sure that this gets printed.
409 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
410  std::cerr
411  << "RCPNodeTracer::addNewRCPNode(...): Adding "
412  << convertRCPNodeToString(rcp_node) << " ...\n";
413 #endif
414 
415  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
416 
417  const void * const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
418 
419  // See if the rcp_node or its object has already been added.
420  typedef rcp_node_list_t::iterator itr_t;
421  typedef std::pair<itr_t, itr_t> itr_itr_t;
422  const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr);
423  const bool rcp_node_already_exists = itr_itr.first != itr_itr.second;
424  RCPNode *previous_rcp_node = 0;
425  bool previous_rcp_node_has_ownership = false;
426  for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
427  previous_rcp_node = itr->second.nodePtr;
428  if (previous_rcp_node->has_ownership()) {
429  previous_rcp_node_has_ownership = true;
430  break;
431  }
432  }
434  rcp_node_already_exists && rcp_node->has_ownership() && previous_rcp_node_has_ownership,
436  "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n"
437  "RCPNode object to an existing managed object in another RCPNode:\n"
438  "\n"
439  " New " << convertRCPNodeToString(rcp_node) << "\n"
440  "\n"
441  " Existing " << convertRCPNodeToString(previous_rcp_node) << "\n"
442  "\n"
443  " Number current nodes = " << rcp_node_list()->size() << "\n"
444  "\n"
445  "This may indicate that the user might be trying to create a weak RCP to an existing\n"
446  "object but forgot make it non-ownning. Perhaps they meant to use rcpFromRef(...)\n"
447  "or an equivalent function?\n"
448  "\n"
449  << getCommonDebugNotesString();
450  );
451 
452  // NOTE: We allow duplicate RCPNodes if the new node is non-owning. This
453  // might indicate a advanced usage of the RCP class that we want to
454  // support. The typical problem is when the programmer unknowingly
455  // creates an owning RCP to an object already owned by another RCPNode.
456 
457  // Add the new RCP node keyed as described above.
458  (*rcp_node_list()).insert(
459  itr_itr.second,
460  std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
461  );
462  // NOTE: Above, if there is already an existing RCPNode with the same key
463  // value, this iterator itr_itr.second will point to one after the found
464  // range. I suspect that this might also ensure that the elements are
465  // sorted in natural order.
466 
467  // Update the insertion number an node tracing statistics
468  ++insertionNumber;
469  ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
470  loc_rcpNodeStatistics().maxNumRCPNodes =
471  TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes());
472  }
473 }
474 
475 
476 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
477  TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \
478  std::logic_error, \
479  "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \
480  << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \
481  " active RCP nodes being traced even though all nodes should be traced." \
482  " This should not be possible and can only be an internal programming error!")
483 
484 
485 void RCPNodeTracer::removeRCPNode( RCPNode* rcp_node )
486 {
487 
488  // Here, we will try to remove an RCPNode reguardless if whether
489  // loc_isTracingActiveRCPNodes==true or not. This will not be a performance
490  // problem and it will ensure that any RCPNode objects that are added to
491  // this list will be removed and will not look like a memory leak. In
492  // non-debug mode, this function will never be called. In debug mode, with
493  // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
494  // therefore this find(...) operation should be pretty cheap (even for a bad
495  // implementation of std::map).
496 
497  TEUCHOS_ASSERT(rcp_node_list());
498  typedef rcp_node_list_t::iterator itr_t;
499  typedef std::pair<itr_t, itr_t> itr_itr_t;
500 
501  const itr_itr_t itr_itr =
502  rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node));
503  const bool rcp_node_exists = itr_itr.first != itr_itr.second;
504 
505 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
506  // If we have the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned on a
507  // compile time, then all RCPNode objects that get created will have been
508  // added to this list. In this case, we can asset that the node exists.
509  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
510 #else
511  // If the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned off, then is is
512  // possible that an RCP got created before the bool
513  // loc_isTracingActiveRCPNodes was turned on. In this case, we must allow
514  // for an RCP node not to have been added to this list. In this case we
515  // will just let this go!
516 #endif
517 
518  if (rcp_node_exists) {
519 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
520  std::cerr
521  << "RCPNodeTracer::removeRCPNode(...): Removing "
522  << convertRCPNodeToString(rcp_node) << " ...\n";
523 #endif
524  bool foundRCPNode = false;
525  for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
526  if (itr->second.nodePtr == rcp_node) {
527  rcp_node_list()->erase(itr);
528  ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions;
529  foundRCPNode = true;
530  break;
531  }
532  }
533  // Whoops! Did not find the node!
534  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
535  }
536 
537 }
538 
539 
540 RCPNode* RCPNodeTracer::getExistingRCPNodeGivenLookupKey(const void* p)
541 {
542  typedef rcp_node_list_t::iterator itr_t;
543  typedef std::pair<itr_t, itr_t> itr_itr_t;
544  if (!p)
545  return 0;
546  const itr_itr_t itr_itr = rcp_node_list()->equal_range(p);
547  for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
548  RCPNode* rcpNode = itr->second.nodePtr;
549  if (rcpNode->has_ownership()) {
550  return rcpNode;
551  }
552  }
553  return 0;
554  // NOTE: Above, we return the first RCPNode added that has the given key
555  // value.
556 }
557 
558 
559 std::string RCPNodeTracer::getActiveRCPNodeHeaderString()
560 {
561  return std::string(
562  "\n***"
563  "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
564  "\n*** not been destroyed yet. A memory checking tool may complain that these"
565  "\n*** objects are not destroyed correctly."
566  "\n***"
567  "\n*** There can be many possible reasons that this might occur including:"
568  "\n***"
569  "\n*** a) The program called abort() or exit() before main() was finished."
570  "\n*** All of the objects that would have been freed through destructors"
571  "\n*** are not freed but some compilers (e.g. GCC) will still call the"
572  "\n*** destructors on static objects (which is what causes this message"
573  "\n*** to be printed)."
574  "\n***"
575  "\n*** b) The program is using raw new/delete to manage some objects and"
576  "\n*** delete was not called correctly and the objects not deleted hold"
577  "\n*** other objects through reference-counted pointers."
578  "\n***"
579  "\n*** c) This may be an indication that these objects may be involved in"
580  "\n*** a circular dependency of reference-counted managed objects."
581  "\n***\n"
582  );
583 }
584 
585 
586 std::string RCPNodeTracer::getCommonDebugNotesString()
587 {
588  return std::string(
589  "NOTE: To debug issues, open a debugger, and set a break point in the function where\n"
590  "the RCPNode object is first created to determine the context where the object first\n"
591  "gets created. Each RCPNode object is given a unique insertionNumber to allow setting\n"
592  "breakpoints in the code. For example, in GDB one can perform:\n"
593  "\n"
594  "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
595  "\n"
596  "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n"
597  "inserted. In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n"
598  "\n"
599  " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n"
600  " (gdb) cond 1 insertionNumber==3 [ENTER]\n"
601  "\n"
602  "3) Run the program in the debugger. In GDB, do:\n"
603  "\n"
604  " (gdb) run [ENTER]\n"
605  "\n"
606  "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n"
607  );
608 }
609 
610 
611 //
612 // ActiveRCPNodesSetup
613 //
614 
615 
616 ActiveRCPNodesSetup::ActiveRCPNodesSetup()
617 {
618 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
619  std::cerr << "\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ << "\n";
620 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
621  if (!rcp_node_list())
622  rcp_node_list() = new rcp_node_list_t;
623  ++count_;
624 }
625 
626 
627 ActiveRCPNodesSetup::~ActiveRCPNodesSetup()
628 {
629 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
630  std::cerr << "\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ << "\n";
631 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
632  if( --count_ == 0 ) {
633 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
634  std::cerr << "\nPrint active nodes!\n";
635 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
636  std::cout << std::flush;
637  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
638  RCPNodeTracer::RCPNodeStatistics rcpNodeStatistics =
639  RCPNodeTracer::getRCPNodeStatistics();
640  if (rcpNodeStatistics.maxNumRCPNodes
641  && RCPNodeTracer::getPrintRCPNodeStatisticsOnExit())
642  {
643  RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout);
644  }
645  RCPNodeTracer::printActiveRCPNodes(std::cerr);
646  delete rcp_node_list();
647  rcp_node_list() = 0;
648  }
649 }
650 
651 
653 {
654  int dummy = count_;
655  ++dummy; // Avoid unused variable warning (bug 2664)
656 }
657 
658 
659 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
660 
661 
662 //
663 // RCPNodeHandle
664 //
665 
666 
667 void RCPNodeHandle::unbindOne()
668 {
669  if (node_) {
670  // NOTE: We only deincrement the reference count after
671  // we have called delete on the underlying object since
672  // that call to delete may actually thrown an exception!
673  if (node_->strong_count()==1 && strength()==RCP_STRONG) {
674  // Delete the object (which might throw)
675  node_->delete_obj();
676  #ifdef TEUCHOS_DEBUG
677  // We actaully also need to remove the RCPNode from the active list for
678  // some specialized use cases that need to be able to create a new RCP
679  // node pointing to the same memory. What this means is that when the
680  // strong count goes to zero and the referenced object is destroyed,
681  // then it will not longer be picked up by any other code and instead it
682  // will only be known by its remaining weak RCPNodeHandle objects in
683  // order to perform debug-mode runtime checking in case a client tries
684  // to access the obejct.
685  local_activeRCPNodesSetup.foo(); // Make sure created!
686  RCPNodeTracer::removeRCPNode(node_);
687 #endif
688  }
689  // If we get here, no exception was thrown!
690  if ( (node_->strong_count() + node_->weak_count()) == 1 ) {
691  // The last RCP object is going away so time to delete
692  // the entire node!
693  delete node_;
694  node_ = 0;
695  // NOTE: No need to deincrement the reference count since this is
696  // the last RCP object being deleted!
697  }
698  else {
699  // The last RCP has not gone away so just deincrement the reference
700  // count.
701  node_->deincr_count(strength());
702  }
703  }
704 }
705 
706 
707 } // namespace Teuchos
708 
709 
710 //
711 // Non-member helpers
712 //
713 
714 
715 void Teuchos::throw_null_ptr_error( const std::string &type_name )
716 {
718  true, NullReferenceError,
719  type_name << " : You can not call operator->() or operator*()"
720  <<" if getRawPtr()==0!" );
721 }
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...