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 
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 
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 
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 
323 {
324  return loc_rcpNodeStatistics();
325 }
326 
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 
342  bool printRCPNodeStatisticsOnExit)
343 {
344  loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
345 }
346 
347 
349 {
350  return loc_printRCPNodeStatisticsOnExit();
351 }
352 
353 
354 void RCPNodeTracer::setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit)
355 {
356  loc_printActiveRcpNodesOnExit() = printActiveRcpNodesOnExit;
357 }
358 
359 
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) {
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"
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"
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 
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 
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 
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 
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 
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 
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 =
659  if (rcpNodeStatistics.maxNumRCPNodes
661  {
662  RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout);
663  }
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!
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 }
static void printRCPNodeStatistics(const RCPNodeStatistics &rcpNodeStatistics, std::ostream &out)
Print the RCPNode allocation statistics.
static bool isTracingActiveRCPNodes()
Return if we are tracing active nodes or not.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
int deincr_count(const ERCPStrength strength)
static void setPrintRCPNodeStatisticsOnExit(bool printRCPNodeStatisticsOnExit)
Set if RCPNode usage statistics will be printed when the program ends or not.
void set_extra_data(const any &extra_data, const std::string &name, EPrePostDestruction destroy_when, bool force_unique)
static RCPNodeStatistics getRCPNodeStatistics()
Return the statistics on RCPNode allocations.
Modified boost::any class, which is a container for a templated value.
Definition: Teuchos_any.hpp:86
int weak_count() const
any & get_extra_data(const std::string &type_name, const std::string &name)
void has_ownership(bool has_ownership_in)
static std::string getCommonDebugNotesString()
Common error message string on how to debug RCPNode problems.
static bool getPrintRCPNodeStatisticsOnExit()
Return if RCPNode usage statistics will be printed when the program ends or not.
Node class to keep track of address and the reference count for a reference-counted utility class and...
static RCPNode * getExistingRCPNodeGivenLookupKey(const void *lookupKey)
Return a raw pointer to an existing owning RCPNode given its lookup key.
static bool getPrintActiveRcpNodesOnExit()
Return if printActiveRCPNodes() is called on exit from the program.
virtual const std::string get_base_obj_type_name() const =0
int strong_count() const
ERCPStrength strength() const
The strength of this handle.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos, as well as a number of utility routines.
virtual void delete_obj()=0
std::string typeName() const
Return the name of the type.
any * get_optional_extra_data(const std::string &type_name, const std::string &name)
static void removeRCPNode(RCPNode *rcp_node)
Remove an RCPNode from global list.
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.
static std::string getActiveRCPNodeHeaderString()
Header string used in printActiveRCPNodes().
static int numActiveRCPNodes()
Print the number of active RCPNode objects currently being tracked.
static void addNewRCPNode(RCPNode *rcp_node, const std::string &info)
Add new RCPNode to the global list.
#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...
static void printActiveRCPNodes(std::ostream &out)
Print the list of currently active RCP nodes.
static void setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit)
Set if printActiveRCPNodes() is called on exit from the program.