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_RCP.hpp"
43 #include "Teuchos_GlobalMPISession.hpp"
44 #include "Teuchos_oblackholestream.hpp"
45 #include "Teuchos_CommandLineProcessor.hpp"
46 #include "Teuchos_StandardCatchMacros.hpp"
47 #include "Teuchos_Assert.hpp"
48 #include "Teuchos_getConst.hpp"
49 #include "Teuchos_Version.hpp"
50
51 #ifdef HAVE_TEUCHOS_BOOST
52 # include "Teuchos_RCPBoostSharedPtrConversions.hpp"
53 #endif
54
55 #include "TestClasses.hpp"
56
57
58 //
59 // Uncomment these macros to see example errors
60 //
61
62 //#define SHOW_COMPILE_TIME_ERRORS
63 //#define SHOW_RUN_TIME_ERROR_1
64 //#define SHOW_RUN_TIME_ERROR_2
65 //#define SHOW_RUN_TIME_ERROR_3
66 //#define SHOW_RUN_TIME_ERROR_4
67 #define SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS
68 #define SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS_PRINT
69 //#define SHOW_MEMORY_LEAK_1
70
71 //
72 // This program prints minimal output to standard error
73 //
74
main(int argc,char * argv[])75 int main( int argc, char* argv[] ) {
76
77 using Teuchos::RCP;
78 using Teuchos::DeallocDelete;
79 using Teuchos::deallocFunctorDelete;
80 using Teuchos::deallocFunctorHandleDelete;
81 using Teuchos::null;
82 using Teuchos::rcp;
83 using Teuchos::rcpFromRef;
84 using Teuchos::inOutArg;
85 using Teuchos::is_null;
86 using Teuchos::rcp_implicit_cast;
87 using Teuchos::rcp_const_cast;
88 using Teuchos::rcp_static_cast;
89 using Teuchos::rcp_dynamic_cast;
90 using Teuchos::set_extra_data;
91 using Teuchos::get_extra_data;
92 using Teuchos::get_nonconst_extra_data;
93 using Teuchos::get_optional_extra_data;
94 using Teuchos::get_optional_nonconst_extra_data;
95 using Teuchos::get_dealloc;
96 using Teuchos::get_nonconst_dealloc;
97 using Teuchos::get_optional_dealloc;
98 using Teuchos::get_optional_nonconst_dealloc;
99 using Teuchos::rcpWithEmbeddedObj;
100 using Teuchos::rcpWithEmbeddedObjPreDestroy;
101 using Teuchos::rcpWithEmbeddedObjPostDestroy;
102 using Teuchos::getEmbeddedObj;
103 using Teuchos::getNonconstEmbeddedObj;
104 using Teuchos::getConst;
105 using Teuchos::CommandLineProcessor;
106
107 bool success = true;
108 bool createCircRefs = false; // Don't create memory leak by default!
109
110 Teuchos::GlobalMPISession mpiSession(&argc,&argv);
111 const int procRank = Teuchos::GlobalMPISession::getRank();
112
113 Teuchos::oblackholestream blackhole;
114 std::ostream &out = ( procRank == 0 ? std::cout : blackhole );
115
116 try {
117
118 // Read options from the commandline
119 CommandLineProcessor clp(false); // Don't throw exceptions
120 clp.setOption( "create-circ-refs", "no-create-circ-refs", &createCircRefs,
121 "Set if output is printed or not." );
122 CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
123 if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) {
124 out << "\nEnd Result: TEST FAILED" << std::endl;
125 return parse_return;
126 }
127
128 blackhole << "\nThis should not print anywhere.\n";
129
130 out << std::endl << Teuchos::Teuchos_Version() << std::endl;
131
132 out << "\nTesting basic RCP functionality ...\n";
133
134 // Create some smart pointers
135
136 RCP<A> a_ptr1 = rcp(new C);
137 out << "\na_ptr1 = " << a_ptr1 << "\n";
138 // RAB: 2003/11/24: The Sun compiler ("Forte Developer 7 C++
139 // 5.4 2002/03/09" returned from CC -V) does not seem to be
140 // following the standard when it comes to the handling of
141 // temporary objects and therefore the count() is not currect.
142 // In the above statement, at least one and perhaps two
143 // temporary RCP objects are created before the object
144 // a_ptr1 is initialized. However, the standard says that the
145 // lifetime of temprary objects must not extend past the
146 // statement in which it was created (see section 10.4.10 in
147 // Stroustroup, 3ed edition). This compiler stinks!!!!!
148 TEUCHOS_TEST_FOR_EXCEPT( a_ptr1.strong_count() != 1 );
149 TEUCHOS_TEST_FOR_EXCEPT( !a_ptr1.shares_resource(a_ptr1) );
150 TEUCHOS_TEST_FOR_EXCEPT( a_ptr1.ptr() == null );
151 TEUCHOS_TEST_FOR_EXCEPT( a_ptr1 == null );
152 TEUCHOS_TEST_FOR_EXCEPT( !(a_ptr1 != null) );
153 TEUCHOS_TEST_FOR_EXCEPT( is_null(a_ptr1) );
154 RCP<D> d_ptr1 = rcp(new E);
155 TEUCHOS_TEST_FOR_EXCEPT( d_ptr1.shares_resource(a_ptr1) );
156 TEUCHOS_TEST_FOR_EXCEPT( d_ptr1.strong_count() != 1 );
157 TEUCHOS_TEST_FOR_EXCEPT( d_ptr1.get() == NULL);
158 TEUCHOS_TEST_FOR_EXCEPT( d_ptr1.getRawPtr() == NULL);
159
160 {
161
162 // Create some more smart points (no new memory!)
163
164 const RCP<const A> ca_ptr1 = rcp_const_cast<const A>(a_ptr1);
165 TEUCHOS_TEST_FOR_EXCEPT( !(ca_ptr1 == a_ptr1) );
166 TEUCHOS_TEST_FOR_EXCEPT( ca_ptr1 != a_ptr1 );
167 TEUCHOS_TEST_FOR_EXCEPT( !ca_ptr1.shares_resource(a_ptr1) );
168 TEUCHOS_TEST_FOR_EXCEPT( a_ptr1.strong_count() != 2 );
169 TEUCHOS_TEST_FOR_EXCEPT( ca_ptr1.ptr() == null );
170 TEUCHOS_TEST_FOR_EXCEPT( ca_ptr1.strong_count() != 2 );
171 const RCP<const D> cd_ptr1 = rcp_const_cast<const D>(d_ptr1);
172 TEUCHOS_TEST_FOR_EXCEPT( d_ptr1.strong_count() != 2 );
173 TEUCHOS_TEST_FOR_EXCEPT( cd_ptr1.ptr() == null );
174 TEUCHOS_TEST_FOR_EXCEPT( cd_ptr1.strong_count() != 2 );
175
176 #ifdef SHOW_RUN_TIME_ERROR_1
177 // Conversion using get() is a no no! When a_ptr2 is deleted so will the allocated
178 // object and then a_ptr1 will be corrupted after this block ends!
179 const RCP<A> a_ptr2 = a_ptr1.get();
180 #endif
181
182 // Test assignment functions
183
184 a_ptr1 = rcp_const_cast<A>(ca_ptr1.assert_not_null()); // Should be okay, assignment to self
185
186 #ifdef SHOW_COMPILE_TIME_ERRORS
187 ca_ptr1 = ca_ptr1; // Should not compile since ca_ptr1 is declared constant
188 ca_ptr1->A_g(); // Should not compile since A_g() is a non-const member function
189 #endif
190
191 // Test function calls through operaor->(...)
192
193 TEUCHOS_TEST_FOR_EXCEPT( a_ptr1->A_g() != A_g_return );
194 TEUCHOS_TEST_FOR_EXCEPT( a_ptr1->A_f() != A_f_return );
195 TEUCHOS_TEST_FOR_EXCEPT( ca_ptr1->A_f() != A_f_return );
196 TEUCHOS_TEST_FOR_EXCEPT( d_ptr1->D_g() != D_g_return );
197 TEUCHOS_TEST_FOR_EXCEPT( d_ptr1->D_f() != D_f_return );
198 TEUCHOS_TEST_FOR_EXCEPT( cd_ptr1->D_f() != D_f_return );
199
200 // Test funciton calls through operator*(...)
201
202 TEUCHOS_TEST_FOR_EXCEPT( (*a_ptr1).A_g() != A_g_return );
203 TEUCHOS_TEST_FOR_EXCEPT( (*a_ptr1).A_f() != A_f_return );
204 TEUCHOS_TEST_FOR_EXCEPT( (*ca_ptr1).A_f() != A_f_return );
205 TEUCHOS_TEST_FOR_EXCEPT( (*d_ptr1).D_g() != D_g_return );
206 TEUCHOS_TEST_FOR_EXCEPT( (*d_ptr1).D_f() != D_f_return );
207 TEUCHOS_TEST_FOR_EXCEPT( (*cd_ptr1).D_f() != D_f_return );
208
209 // Test dynamic and static conversions
210
211 // Cast down the inheritance hiearchy (const A -> const B1)
212 const RCP<const B1> cb1_ptr1 = rcp_dynamic_cast<const B1>(ca_ptr1);
213 TEUCHOS_TEST_FOR_EXCEPT( cb1_ptr1.ptr() == null );
214 TEUCHOS_TEST_FOR_EXCEPT( cb1_ptr1.strong_count() != 3 );
215 TEUCHOS_TEST_FOR_EXCEPT( ca_ptr1.strong_count() != 3 );
216 TEUCHOS_TEST_FOR_EXCEPT( a_ptr1.strong_count() != 3 );
217
218 // Cast up the inheritance hiearchy (const B1 -> const A)
219 TEUCHOS_TEST_FOR_EXCEPT( rcp_implicit_cast<const A>(cb1_ptr1)->A_f() != A_f_return );
220 TEUCHOS_TEST_FOR_EXCEPT( RCP<const A>(cb1_ptr1)->A_f() != A_f_return );
221 // Implicit cast from const to non-const (A -> const A)
222 TEUCHOS_TEST_FOR_EXCEPT( rcp_implicit_cast<const A>(a_ptr1)->A_f() != A_f_return );
223 TEUCHOS_TEST_FOR_EXCEPT( RCP<const A>(a_ptr1)->A_f() != A_f_return );
224 // Cast away constantness (const B1 -> B1)
225 TEUCHOS_TEST_FOR_EXCEPT( rcp_const_cast<B1>(cb1_ptr1)->B1_g() != B1_g_return );
226 // Cast across the inheritance hiearchy (const B1 -> const B2)
227 TEUCHOS_TEST_FOR_EXCEPT( rcp_dynamic_cast<const B2>(cb1_ptr1)->B2_f() != B2_f_return );
228 // Cast down the inheritance hiearchy (const B1 -> const C)
229 TEUCHOS_TEST_FOR_EXCEPT( rcp_dynamic_cast<const C>(cb1_ptr1)->C_f() != C_f_return );
230
231 // Cast away constantness (const C -> C)
232 const RCP<C>
233 c_ptr1 = rcp_const_cast<C>(rcp_dynamic_cast<const C>(ca_ptr1));
234 TEUCHOS_TEST_FOR_EXCEPT( c_ptr1.ptr() == null );
235 TEUCHOS_TEST_FOR_EXCEPT( c_ptr1.strong_count() != 4 );
236 TEUCHOS_TEST_FOR_EXCEPT( ca_ptr1.strong_count() != 4 );
237 TEUCHOS_TEST_FOR_EXCEPT( a_ptr1.strong_count() != 4 );
238
239 // Cast down the inheritance hiearchy using static_cast<...> (const D -> const E)
240 const RCP<const E>
241 ce_ptr1 = rcp_static_cast<const E>(cd_ptr1); // This is not checked at runtime!
242 TEUCHOS_TEST_FOR_EXCEPT( ce_ptr1.ptr() == null);
243 TEUCHOS_TEST_FOR_EXCEPT( ce_ptr1.strong_count() != 3 );
244 TEUCHOS_TEST_FOR_EXCEPT( cd_ptr1.strong_count() != 3 );
245 TEUCHOS_TEST_FOR_EXCEPT( d_ptr1.strong_count() != 3 );
246
247 // Cast up the inheritance hiearchy (const E -> const D)
248 TEUCHOS_TEST_FOR_EXCEPT( rcp_implicit_cast<const D>(ce_ptr1)->D_f() != D_f_return );
249 // Cast away constantness (const E -> E)
250 TEUCHOS_TEST_FOR_EXCEPT( rcp_const_cast<E>(ce_ptr1)->E_g() != E_g_return );
251 TEUCHOS_TEST_FOR_EXCEPT( ce_ptr1->D_f() != D_f_return );
252
253 #ifdef SHOW_COMPILE_TIME_ERRORS
254 // Try to cast down inheritance hiearchy using dynamic_cast<...> (const D -> const E)
255 rcp_dynamic_cast<const E>( cd_ptr1 )->E_f(); // This should not compile since D and E are not polymophic
256 #endif
257
258 #ifndef _INTEL // Intel compiler does not seem to be doing dynamic cast correctly?
259 #ifdef TEUCHOS_DEBUG // operator->() only throws std::exception when TEUCHOS_DEBUG is defined
260 try {
261 // Try to cast form one interface to another that is not supported (B2 -> B1).
262 // The RCP<B1> returned from rcp_dynamic_cast<...> should be null!
263 // Note that RCP<...>::optertor->() should throw an std::exception in debug
264 // mode (i.e. TEUCHOS_DEBUG is defined) but even so no memory leak occurs. If you
265 // don't believe me then step through with a debugger and see for yourself.
266 TEUCHOS_TEST_FOR_EXCEPT( rcp_dynamic_cast<B1>( rcp(new B2) )->B1_g() != B1_g_return );
267 return -1; // Should not be executed!
268 }
269 catch( const std::logic_error &excpt )
270 {}
271 #endif
272 try {
273 // Try to cast form one interface to another that is not supported (B2 -> B1).
274 // Note that rcp_dynamic_cast<B1>(...,true) should throw an std::exception but even
275 // so no memory leak occurs. If you don't believe me then step through with a
276 // debugger and see for yourself.
277 rcp_dynamic_cast<B1>( rcp(new B2), true );
278 return -1; // Should not be executed!
279 }
280 catch( const std::bad_cast &excpt )
281 {}
282 #endif
283
284 // Manually clean up some memory
285
286 delete d_ptr1.release().get(); // Now d_ptr1.get() no longer points to a valid object but okay
287 // as long as no other access to this object is attempted! (see below)
288 #ifdef SHOW_RUN_TIME_ERROR_2
289 TEUCHOS_TEST_FOR_EXCEPT( d_ptr1->D_g() == D_g_return ); // Should cause a segmentation fault since d_ptr.get() was deleted!
290 #endif
291
292 #ifdef SHOW_MEMORY_LEAK_1
293 a_ptr1.release(); // If we release but do not delete manually then this is a memory leak!
294 #endif
295
296 // Here at the end of the block, all of the other smart pointers are deleted!
297 }
298 // Check that all of the other references where removed but these
299 TEUCHOS_TEST_FOR_EXCEPT( a_ptr1.strong_count() != 1 );
300 TEUCHOS_TEST_FOR_EXCEPT( d_ptr1.strong_count() != 1 );
301
302 // Assign some other dynamically created objects.
303
304 a_ptr1 = rcp(new A); // In each case the current dynamically allocated object is deleted ...
305 a_ptr1 = rcp(new B1); // before the new reference is set.
306 a_ptr1 = rcp(new B2); // ""
307 a_ptr1 = rcp(new C); // ""
308 d_ptr1 = rcp(new D); // ""
309 d_ptr1 = rcp(new E); // ""
310
311 // Assign pointers to some automatic objects that do not need deleted.
312 // We can do this but we need to remove ownership of the pointer
313 // from the smart pointer objects so that they do not try to
314 // delete them. If we forget then delete will be called on these
315 // pointers and will cause a runtime error.
316
317 C c; // Automatic object what will be deleted by compiler at end of block
318 a_ptr1 = rcp(&c);
319 #ifndef SHOW_RUN_TIME_ERROR_3
320 // Release ownership so that a_ptr1 will not try to delete &c when a_ptr1 goes out of scope
321 a_ptr1.release();
322 #endif
323
324 E e; // Automatic object what will be deleted by compiler at end of block
325 d_ptr1 = rcp(&e);
326 #ifndef SHOW_RUN_TIME_ERROR_4
327 // Release ownership so that d_ptr1 will not try to delete &e when a_ptr1 goes out of scope
328 d_ptr1.release();
329 #endif
330
331 #ifdef SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS
332 // Allocate an using new and then store the non-base address in in
333 // a RCP and then try to delete (this is a no-no usually).
334 C *c_ptr5 = new C; // Okay, no type info lost and address should be same as returned from malloc(...)
335 #ifdef SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS_PRINT
336 const void *c_ptr5_base = dynamic_cast<void*>(c_ptr5);
337 out << "\nSize of C = " << sizeof(C) << std::endl;
338 out << "Base address of object of type C = " << dynamic_cast<void*>(c_ptr5) << std::endl;
339 out << "Offset to address of object of type C = " << ((long int)c_ptr5 - (long int)c_ptr5_base) << std::endl;
340 out << "Offset of B1 object in object of type C = " << ((long int)static_cast<B1*>(c_ptr5) - (long int)c_ptr5_base) << std::endl;
341 out << "Offset of B2 object in object of type C = " << ((long int)static_cast<B2*>(c_ptr5) - (long int)c_ptr5_base) << std::endl;
342 out << "Offset of A object in object of type C = " << ((long int)static_cast<A*>(c_ptr5) - (long int)c_ptr5_base) << std::endl;
343 #endif // SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS_PRINT
344 A *a_rptr5 = c_ptr5; // Here the address has changed and is no longer the same as the base address
345 a_ptr1 = rcp(a_rptr5); // This is a no-no and could cause trouble!
346 a_ptr1 = null; // This will cause a segmentation fault in free(...) on many platforms
347 #endif // SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS
348
349 // Test out getting the deallocator object
350 a_ptr1 = rcpWithDealloc( new C, DeallocDelete<C>() );
351 get_dealloc<DeallocDelete<C> >(a_ptr1);
352 get_nonconst_dealloc<DeallocDelete<C> >(a_ptr1);
353 TEUCHOS_TEST_FOR_EXCEPT( get_optional_nonconst_dealloc<DeallocDelete<C> >(a_ptr1)==null );
354 TEUCHOS_TEST_FOR_EXCEPT( get_optional_nonconst_dealloc<DeallocDelete<A> >(a_ptr1)!=null );
355 TEUCHOS_TEST_FOR_EXCEPT( get_optional_dealloc<DeallocDelete<C> >(const_cast<const RCP<A>&>(a_ptr1))==null );
356 TEUCHOS_TEST_FOR_EXCEPT( get_optional_dealloc<DeallocDelete<A> >(const_cast<const RCP<A>&>(a_ptr1))!=null );
357
358 // Test storing extra data and then getting it out again
359 TEUCHOS_TEST_FOR_EXCEPT( get_optional_nonconst_extra_data<RCP<B1> >(a_ptr1,"blahblah") != null );
360 TEUCHOS_TEST_FOR_EXCEPT( get_optional_extra_data<int>(const_cast<const RCP<A>&>(a_ptr1),"blahblah") != null ); // test const version
361 set_extra_data( int(-5), "int", inOutArg(a_ptr1) );
362 TEUCHOS_TEST_FOR_EXCEPT( get_extra_data<int>(a_ptr1,"int") != -5 );
363 TEUCHOS_TEST_FOR_EXCEPT( get_nonconst_extra_data<int>(a_ptr1,"int") != -5 );
364 set_extra_data( rcp(new B1), "B1", inOutArg(a_ptr1) );
365 TEUCHOS_TEST_FOR_EXCEPT( get_extra_data<RCP<B1> >(a_ptr1,"B1")->B1_f() != B1_f_return );
366 TEUCHOS_TEST_FOR_EXCEPT( get_extra_data<int>(const_cast<const RCP<A>&>(a_ptr1),"int") != -5 ); // test const version
367 TEUCHOS_TEST_FOR_EXCEPT( (*get_optional_extra_data<RCP<B1> >(a_ptr1,"B1"))->B1_f() != B1_f_return );
368 TEUCHOS_TEST_FOR_EXCEPT( *get_optional_extra_data<int>(const_cast<const RCP<A>&>(a_ptr1),"int") != -5 ); // test const version
369 TEUCHOS_TEST_FOR_EXCEPT( get_optional_extra_data<RCP<B1> >(a_ptr1,"blahblah") != null );
370 TEUCHOS_TEST_FOR_EXCEPT( get_optional_extra_data<int>(const_cast<const RCP<A>&>(a_ptr1),"blahblah") != null ); // test const version
371
372 // Test storage of extra data as embedded objects and then getting it out
373 // again
374
375 {
376 RCP<A> a_ptr = rcpWithEmbeddedObj(new C,int(-5));
377 const int intRtn1 = getEmbeddedObj<C,int>(a_ptr);
378 TEUCHOS_TEST_FOR_EXCEPT( intRtn1 != -5 );
379 getNonconstEmbeddedObj<C,int>(a_ptr) = -4;
380 const int intRtn2 = getEmbeddedObj<C,int>(a_ptr);
381 TEUCHOS_TEST_FOR_EXCEPT( intRtn2 != -4 );
382 }
383
384 {
385 RCP<A> a_ptr = rcpWithEmbeddedObjPreDestroy(new C,int(-5));
386 const int intRtn1 = getEmbeddedObj<C,int>(a_ptr);
387 TEUCHOS_TEST_FOR_EXCEPT( intRtn1 != -5 );
388 getNonconstEmbeddedObj<C,int>(a_ptr) = -4;
389 const int intRtn2 = getEmbeddedObj<C,int>(a_ptr);
390 TEUCHOS_TEST_FOR_EXCEPT( intRtn2 != -4 );
391 }
392
393 {
394 RCP<A> a_ptr = rcpWithEmbeddedObjPostDestroy(new C,int(-5));
395 const int intRtn1 = getEmbeddedObj<C,int>(a_ptr);
396 TEUCHOS_TEST_FOR_EXCEPT( intRtn1 != -5 );
397 getNonconstEmbeddedObj<C,int>(a_ptr) = -4;
398 const int intRtn2 = getEmbeddedObj<C,int>(a_ptr);
399 TEUCHOS_TEST_FOR_EXCEPT( intRtn2 != -4 );
400 }
401
402 // Test pre-destruction of extra data
403 int a_f_return = -2;
404 set_extra_data( rcp(new Get_A_f_return(&*a_ptr1,&a_f_return)),
405 "a_f_return", inOutArg(a_ptr1), Teuchos::PRE_DESTROY );
406
407 // Set pointers to null to force releasing any owned memory
408 a_ptr1 = null;
409 d_ptr1 = null;
410
411 // RAB: 2004/08/12: It appears that SUN compiler is not deleting the piece of extra
412 // data properly and therefore the destructor of the above Get_A_f_return object
413 // is not being called (which sets the value of af_return). This compiler stinks!
414 TEUCHOS_TEST_FOR_EXCEPT( a_f_return != A_f_return ); // Should be been called in destructor of a_ptr1 but before the A object is destroyed!
415
416 // Testing the deallocFunctorDelete function and DeallocFunctorDelete class
417 a_ptr1 = rcpWithDealloc( new C, deallocFunctorDelete<A>(deallocA) );
418 a_ptr1 = null;
419
420 // Testing the deallocFunctorHandleDelete function and DeallocFunctorHandleDelete class
421 a_ptr1 = rcpWithDealloc( new C, deallocFunctorHandleDelete<A>(deallocHandleA) );
422 a_ptr1 = null;
423
424 #ifdef TEUCHOS_DEBUG
425
426 if (createCircRefs) {
427 out << "\nCreate a circular reference that will cause a memory leak! ...\n";
428 # if !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
429 // Only trun on tracing if you have to
430 Teuchos::RCPNodeTracer::setTracingActiveRCPNodes(true);
431 # endif
432 RCP<A> a = rcp(new A());
433 RCP<C> c2 = rcp(new C());
434 a->set_C(c2);
435 c2->set_A(a);
436 }
437
438 #endif // TEUCHOS_DEBUG
439
440 #ifndef TEUCHOS_DEBUG
441
442 out << "\nTesting using RCP to wrap an undefined opaque object (no TNT) ...\n";
443 {
444 RCP<UndefinedType> op_ptr =
445 rcpWithDeallocUndef (createOpaque (),
446 deallocFunctorHandleDelete<UndefinedType> (destroyOpaque),
447 true);
448 TEUCHOS_ASSERT_EQUALITY( getOpaqueValue(&*op_ptr), getOpaqueValue_return );
449 }
450 // 2008/08/01: rabartl: Above, we can only wrap an undefined type in
451 // nondebug mode since there is no TypeNameTraits class defined for it and
452 // the default uses typeid(...) which you can't call on an undefined type.
453 // If you define a specialization of TypeNameTraits for this class, then
454 // it will compile just fine! This is related to bug 4016.
455
456 #endif // not TEUCHOS_DEBUG
457
458 out << "\nTesting using RCP to wrap an undefined opaque object (with TNT) ...\n";
459 {
460 RCP<UndefinedType2> op_ptr = rcpWithDeallocUndef( createOpaque2(),
461 deallocFunctorHandleDelete<UndefinedType2>(destroyOpaque2) );
462 TEUCHOS_ASSERT_EQUALITY( getOpaque2Value(&*op_ptr), getOpaque2Value_return );
463 }
464 // 2008/08/01: rabartl: Above, we can wrap an undefined type in debug mode
465 // as long as we have a TypeNameTraits specialization of it to avoid
466 // calling typeid(...).
467
468 #ifdef HAVE_TEUCHOS_BOOST
469
470 out << "\nTesting basic RCP compatibility with boost::shared_ptr ...\n";
471
472 boost::shared_ptr<A> a_sptr1(new C());
473 RCP<A> a_rsptr1 = rcp(a_sptr1);
474 TEUCHOS_TEST_FOR_EXCEPT( a_rsptr1.get() != a_sptr1.get() );
475 TEUCHOS_TEST_FOR_EXCEPT( a_rsptr1.getRawPtr() != a_sptr1.get() );
476 TEUCHOS_TEST_FOR_EXCEPT( a_rsptr1.get() != a_rsptr1.getRawPtr() );
477 boost::shared_ptr<A> a_sptr2 = shared_pointer(a_rsptr1);
478 // There seems no standard way to test that a shared_ptr shares the same node
479 //TEUCHOS_TEST_FOR_EXCEPT( a_sptr2._internal_equiv(a_sptr1) != true );
480 RCP<A> a_rsptr2 = rcp(a_sptr2);
481 TEUCHOS_TEST_FOR_EXCEPT( a_rsptr2.ptr() != a_rsptr1.ptr() );
482 //TEUCHOS_TEST_FOR_EXCEPT( a_rsptr2 != a_rsptr1 ); // This should work if boost::get_deleter() works correctly!
483 boost::shared_ptr<A> a_sptr3 = shared_pointer(a_rsptr2);
484 TEUCHOS_TEST_FOR_EXCEPT( a_sptr3.get() != a_rsptr2.get() );
485
486 out << "\nCompatibility with boost::shared_ptr passed ...\n";
487
488 #endif // HAVE_TEUCHOS_BOOST
489
490 out << "\nAll tests for RCP seem to check out!\n";
491
492 } // end try
493 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success);
494
495 try {
496 // In debug mode, this should show that the A and C RCP objects are still
497 // around!
498 if (createCircRefs) {
499 out << "\nPrinting the active nodes just to see them!\n";
500 Teuchos::RCPNodeTracer::printActiveRCPNodes(out);
501 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
502 TEUCHOS_ASSERT_EQUALITY( 2, Teuchos::RCPNodeTracer::numActiveRCPNodes() );
503 #endif
504 }
505 } // end try
506 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, std::cerr, success);
507
508 if(success)
509 out << "\nEnd Result: TEST PASSED" << std::endl;
510
511 return ( success ? 0 : 1 );
512
513 }
514