|
Teuchos Package Browser (Single Doxygen Collection) Version of the Day
|
00001 /* 00002 // @HEADER 00003 // *********************************************************************** 00004 // 00005 // Teuchos: Common Tools Package 00006 // Copyright (2004) Sandia Corporation 00007 // 00008 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00009 // license for use of this work by or on behalf of the U.S. Government. 00010 // 00011 // This library is free software; you can redistribute it and/or modify 00012 // it under the terms of the GNU Lesser General Public License as 00013 // published by the Free Software Foundation; either version 2.1 of the 00014 // License, or (at your option) any later version. 00015 // 00016 // This library is distributed in the hope that it will be useful, but 00017 // WITHOUT ANY WARRANTY; without even the implied warranty of 00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 // Lesser General Public License for more details. 00020 // 00021 // You should have received a copy of the GNU Lesser General Public 00022 // License along with this library; if not, write to the Free Software 00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00024 // USA 00025 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00026 // 00027 // *********************************************************************** 00028 // @HEADER 00029 */ 00030 00031 #include "Teuchos_RCP.hpp" 00032 #include "Teuchos_getConst.hpp" 00033 #include "Teuchos_getBaseObjVoidPtr.hpp" 00034 #ifdef HAVE_TEUCHOS_BOOST 00035 # include "Teuchos_RCPBoostSharedPtrConversions.hpp" 00036 #endif 00037 00038 #include "TestClasses.hpp" 00039 00040 #include "Teuchos_UnitTestHarness.hpp" 00041 00042 00043 namespace { 00044 00045 00046 using Teuchos::as; 00047 using Teuchos::null; 00048 using Teuchos::Ptr; 00049 using Teuchos::RCP; 00050 using Teuchos::rcp; 00051 using Teuchos::rcpFromRef; 00052 using Teuchos::rcpFromUndefRef; 00053 using Teuchos::outArg; 00054 using Teuchos::rcpWithEmbeddedObj; 00055 using Teuchos::getEmbeddedObj; 00056 using Teuchos::getOptionalEmbeddedObj; 00057 using Teuchos::getOptionalNonconstEmbeddedObj; 00058 using Teuchos::set_extra_data; 00059 using Teuchos::get_optional_nonconst_extra_data; 00060 using Teuchos::getConst; 00061 using Teuchos::NullReferenceError; 00062 using Teuchos::DanglingReferenceError; 00063 using Teuchos::DuplicateOwningRCPError; 00064 using Teuchos::RCP_STRONG; 00065 using Teuchos::RCP_WEAK; 00066 using Teuchos::RCP_STRENGTH_INVALID; 00067 using Teuchos::RCPNodeTracer; 00068 00069 00070 TEUCHOS_UNIT_TEST( DeallocNull, free ) 00071 { 00072 Teuchos::DeallocNull<A> d; 00073 d.free(0); 00074 } 00075 00076 00077 TEUCHOS_UNIT_TEST( RCP, assignSelf_null ) 00078 { 00079 RCP<A> a_rcp; 00080 a_rcp = a_rcp; 00081 TEST_ASSERT(is_null(a_rcp)); 00082 } 00083 00084 00085 TEUCHOS_UNIT_TEST( RCP, assignSelf_nonnull ) 00086 { 00087 RCP<A> a_rcp(new A); 00088 A *a_raw_ptr = a_rcp.getRawPtr(); 00089 a_rcp = a_rcp; 00090 TEST_ASSERT(nonnull(a_rcp)); 00091 TEST_EQUALITY(a_rcp.getRawPtr(), a_raw_ptr); 00092 } 00093 00094 00095 TEUCHOS_UNIT_TEST( RCP, getConst ) 00096 { 00097 RCP<A> a_rcp(new A); 00098 RCP<const A> ca_rcp = a_rcp.getConst(); 00099 TEST_EQUALITY(a_rcp.getRawPtr(), ca_rcp.getRawPtr()); 00100 } 00101 00102 00103 TEUCHOS_UNIT_TEST( RCP, explicit_null ) 00104 { 00105 RCP<A> a_rcp(0); 00106 TEST_ASSERT(is_null(a_rcp)); 00107 } 00108 00109 00110 TEUCHOS_UNIT_TEST( RCP, explicit_dealloc_null ) 00111 { 00112 RCP<A> a_rcp = rcp<A>(0, Teuchos::DeallocNull<A>(), false); 00113 TEST_ASSERT(is_null(a_rcp)); 00114 } 00115 00116 00117 TEUCHOS_UNIT_TEST( RCP, explicit_null_null ) 00118 { 00119 RCP<A> a_rcp(0, null); 00120 TEST_ASSERT(is_null(a_rcp)); 00121 } 00122 00123 00124 TEUCHOS_UNIT_TEST( RCP, explicit_null_nonnull ) 00125 { 00126 A *a = new A; 00127 RCP<A> a_rcp(a, null); 00128 TEST_ASSERT(nonnull(a_rcp)); 00129 delete a; 00130 } 00131 00132 00133 TEUCHOS_UNIT_TEST( RCP, rcpFromRef_raw_ref ) 00134 { 00135 A a; 00136 RCP<A> a_rcp = rcpFromRef(a); 00137 TEST_EQUALITY(a_rcp.getRawPtr(), &a); 00138 TEST_ASSERT(nonnull(a_rcp)); 00139 } 00140 00141 00142 TEUCHOS_UNIT_TEST( RCP, rcpFromRef_from_rcp ) 00143 { 00144 RCP<A> a_rcp1 = rcp<A>(new A); 00145 RCP<A> a_rcp2 = rcpFromRef(*a_rcp1); 00146 TEST_EQUALITY(a_rcp2.getRawPtr(), a_rcp1.getRawPtr()); 00147 if (RCPNodeTracer::isTracingActiveRCPNodes()) 00148 { 00149 TEST_EQUALITY_CONST(a_rcp2.strong_count(), 1); 00150 TEST_EQUALITY_CONST(a_rcp2.weak_count(), 1); 00151 TEST_EQUALITY_CONST(a_rcp2.has_ownership(), true); 00152 } 00153 else { 00154 TEST_EQUALITY_CONST(a_rcp2.strong_count(), 1); 00155 TEST_EQUALITY_CONST(a_rcp2.weak_count(), 0); 00156 TEST_EQUALITY_CONST(a_rcp2.has_ownership(), false); 00157 } 00158 } 00159 00160 00161 TEUCHOS_UNIT_TEST( RCP, rcpFromUndefRef ) 00162 { 00163 A a; 00164 RCP<A> a_rcp = rcpFromUndefRef(a); 00165 TEST_ASSERT(nonnull(a_rcp)); 00166 } 00167 00168 00169 // 00170 // Test rcpCloneNode(...) 00171 // 00172 00173 00174 TEUCHOS_UNIT_TEST( RCP, rcpCloneNode_null ) 00175 { 00176 ECHO(RCP<RCP<int> > rcp1 = null); 00177 ECHO(RCP<RCP<int> > rcp2 = rcpCloneNode(rcp1)); 00178 TEST_EQUALITY(rcp2, null); 00179 } 00180 00181 00182 TEUCHOS_UNIT_TEST( RCP, rcpCloneNode_basic ) 00183 { 00184 00185 ECHO(RCP<int> rcp1 = rcp(new int(0))); 00186 00187 ECHO(RCP<int> rcp2 = rcpCloneNode(rcp1)); 00188 TEST_ASSERT(nonnull(rcp2)); 00189 TEST_EQUALITY(rcp1.count(), 2); 00190 TEST_EQUALITY(rcp2.count(), 1); 00191 00192 ECHO(RCP<int> rcp3 = rcp2); 00193 TEST_EQUALITY(rcp1.count(), 2); 00194 TEST_EQUALITY(rcp2.count(), 2); 00195 TEST_EQUALITY(rcp3.count(), 2); 00196 00197 ECHO(RCP <int> rcp4 = rcp1); 00198 TEST_EQUALITY(rcp1.count(), 3); 00199 TEST_EQUALITY(rcp2.count(), 2); 00200 TEST_EQUALITY(rcp3.count(), 2); 00201 00202 ECHO(rcp4 = null); 00203 TEST_EQUALITY(rcp1.count(), 2); 00204 TEST_EQUALITY(rcp2.count(), 2); 00205 TEST_EQUALITY(rcp3.count(), 2); 00206 TEST_EQUALITY(rcp4.count(), 0); 00207 00208 ECHO(rcp1 = null); 00209 TEST_EQUALITY(rcp1.count(), 0); 00210 TEST_EQUALITY(rcp2.count(), 2); 00211 TEST_EQUALITY(rcp3.count(), 2); 00212 TEST_EQUALITY(rcp4.count(), 0); 00213 00214 ECHO(rcp2 = null); 00215 TEST_EQUALITY(rcp2.count(), 0); 00216 TEST_EQUALITY(rcp3.count(), 1); 00217 00218 ECHO(rcp3 = null); 00219 TEST_EQUALITY(rcp3.count(), 0); 00220 00221 } 00222 00223 00224 // 00225 // Test duplicate owning RCP objects 00226 // 00227 00228 00229 // Test that shows that we can detect trying to create two owning RCPs 00230 // pointing to the same polymorphic object but having different interfaces 00231 // with different addresses. This happens due to virtual base classes. Only 00232 // works when we have a working getBaseObjVoidPtr(...) function. 00233 TEUCHOS_UNIT_TEST( RCP, duplicate_rcp_owning_polymorphic ) 00234 { 00235 SET_RCPNODE_TRACING(); 00236 ECHO(C *c_ptr = new C); 00237 ECHO(A *a_ptr = c_ptr); 00238 ECHO(RCP<C> c_rcp = rcp(c_ptr)); // Okay 00239 #if defined(TEUCHOS_DEBUG) && defined(HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR) 00240 // With determine they are pointed to the same object! 00241 TEST_THROW(RCP<A> a_rcp = rcp(a_ptr), DuplicateOwningRCPError); 00242 #else 00243 // Will not determine they are point to the same object! 00244 ECHO(RCP<A> a_rcp = rcp(a_ptr)); 00245 TEST_EQUALITY(a_rcp.getRawPtr(), a_ptr); 00246 ECHO(a_rcp.release()); // Better or we will get a segfault! 00247 #endif 00248 } 00249 00250 00251 // Test that shows that we can detect trying to create two owning RCPs 00252 // pointing to the same polymorphic object with the same type and therefore 00253 // the same address. This works even if these use virtual base classes. This 00254 // works even without a working getBaseObjVoidPtr(...) function. 00255 TEUCHOS_UNIT_TEST( RCP, duplicate_rcp_owning_polymorphic_different_addr ) 00256 { 00257 SET_RCPNODE_TRACING(); 00258 ECHO(A *a_ptr1 = new C); 00259 ECHO(A *a_ptr2 = a_ptr1); 00260 ECHO(RCP<A> a_rcp1 = rcp(a_ptr1)); // Okay 00261 #if defined(TEUCHOS_DEBUG) 00262 // With determine they are pointed to the same object! 00263 TEST_THROW(RCP<A> a_rcp2 = rcp(a_ptr2), DuplicateOwningRCPError); 00264 #else 00265 // Will not determine they are point to the same object! 00266 ECHO(RCP<A> a_rcp2 = rcp(a_ptr2)); 00267 TEST_EQUALITY(a_rcp2.getRawPtr(), a_ptr2); 00268 ECHO(a_rcp2.release()); // Better or we will get a segfault! 00269 #endif 00270 } 00271 00272 00273 // Test that shows that we can always detect trying to create two owning RCPs 00274 // pointing to the same nonpolymorphic object having different interfaces but 00275 // the same address (single non-virtual inheritance). Works just fine without 00276 // a working getBaseObjVoidPtr(...) function. 00277 TEUCHOS_UNIT_TEST( RCP, duplicate_rcp_owning_nonpolymorphic_same_addr ) 00278 { 00279 SET_RCPNODE_TRACING(); 00280 ECHO(E *e_ptr = new E); 00281 ECHO(E *d_ptr = e_ptr); 00282 ECHO(RCP<E> e_rcp = rcp(e_ptr)); // Okay 00283 #if defined(TEUCHOS_DEBUG) 00284 // With determine they are pointed to the same object even without support 00285 // for getBaseObjVoidPtr(...) because no dynamic_cast is needed. 00286 TEST_THROW(RCP<D> d_rcp = rcp(d_ptr), DuplicateOwningRCPError); 00287 #else 00288 // Will not determine they are point to the same object! 00289 ECHO(RCP<D> d_rcp = rcp(d_ptr)); 00290 TEST_EQUALITY(d_rcp.getRawPtr(), d_ptr); 00291 ECHO(d_rcp.release()); // Better or we will get a segfault! 00292 #endif 00293 } 00294 00295 00296 // 00297 // These next tests shows that we can detect when two RCPs are create to the same 00298 // object, one owning and the other non-owning. When we have a working 00299 // getBaseObjVoidPtr(...) function, the new non-owning RCP will actually be a 00300 // weak RCP that can be used to detect circular dependencies. 00301 // 00302 00303 00304 // rcp 00305 00306 00307 TEUCHOS_UNIT_TEST( RCP, rcp_duplicate_rcp_nonowning_polymorphic_different_addr ) 00308 { 00309 SET_RCPNODE_TRACING(); 00310 ECHO(RCP<C> c_rcp(new C)); 00311 ECHO(A &a_ref = *c_rcp); 00312 ECHO(RCP<A> a_rcp = rcp(&a_ref, false)); 00313 ECHO(c_rcp = null); 00314 #if defined(TEUCHOS_DEBUG) && defined(HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR) 00315 TEST_THROW(a_rcp->A_g(), DanglingReferenceError); 00316 #else 00317 TEST_NOTHROW(a_rcp.getRawPtr()); 00318 #endif 00319 } 00320 00321 00322 TEUCHOS_UNIT_TEST( RCP, rcp_duplicate_rcp_nonowning_polymorphic_same_addr ) 00323 { 00324 SET_RCPNODE_TRACING(); 00325 ECHO(RCP<A> a_rcp1(new C)); 00326 ECHO(A &a_ref = *a_rcp1); 00327 ECHO(RCP<A> a_rcp2 = rcp(&a_ref, false)); 00328 ECHO(a_rcp1 = null); 00329 #if defined(TEUCHOS_DEBUG) 00330 TEST_THROW(a_rcp2->A_g(), DanglingReferenceError); 00331 #else 00332 TEST_NOTHROW(a_rcp2.getRawPtr()); 00333 #endif 00334 } 00335 00336 00337 TEUCHOS_UNIT_TEST( RCP, rcp_duplicate_rcp_nonowning_nonpolymorphic ) 00338 { 00339 SET_RCPNODE_TRACING(); 00340 ECHO(RCP<E> e_rcp(new E)); 00341 ECHO(D &d_ref = *e_rcp); 00342 ECHO(RCP<D> d_rcp = rcp(&d_ref, false)); 00343 ECHO(e_rcp = null); 00344 #if defined(TEUCHOS_DEBUG) 00345 TEST_THROW(d_rcp->D_g(), DanglingReferenceError); 00346 #else 00347 TEST_NOTHROW(d_rcp.getRawPtr()); 00348 #endif 00349 } 00350 00351 00352 // rcpFromRef 00353 00354 00355 TEUCHOS_UNIT_TEST( RCP, rcpFromRef_duplicate_rcp_nonowning_polymorphic_different_addr ) 00356 { 00357 SET_RCPNODE_TRACING(); 00358 ECHO(RCP<C> c_rcp(new C)); 00359 ECHO(A &a_ref = *c_rcp); 00360 ECHO(RCP<A> a_rcp = rcpFromRef(a_ref)); 00361 ECHO(c_rcp = null); 00362 #if defined(TEUCHOS_DEBUG) && defined(HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR) 00363 TEST_THROW(a_rcp->A_g(), DanglingReferenceError); 00364 #else 00365 TEST_NOTHROW(a_rcp.getRawPtr()); 00366 #endif 00367 } 00368 00369 00370 TEUCHOS_UNIT_TEST( RCP, rcpFromRef_duplicate_rcp_nonowning_polymorphic_same_addr ) 00371 { 00372 SET_RCPNODE_TRACING(); 00373 ECHO(RCP<A> a_rcp1(new C)); 00374 ECHO(A &a_ref = *a_rcp1); 00375 ECHO(RCP<A> a_rcp2 = rcpFromRef(a_ref)); 00376 ECHO(a_rcp1 = null); 00377 #if defined(TEUCHOS_DEBUG) 00378 TEST_THROW(a_rcp2->A_g(), DanglingReferenceError); 00379 #else 00380 TEST_NOTHROW(a_rcp2.getRawPtr()); 00381 #endif 00382 } 00383 00384 00385 TEUCHOS_UNIT_TEST( RCP, rcpFromRef_duplicate_rcp_nonowning_nonpolymorphic ) 00386 { 00387 SET_RCPNODE_TRACING(); 00388 ECHO(RCP<E> e_rcp(new E)); 00389 ECHO(D &d_ref = *e_rcp); 00390 ECHO(RCP<D> d_rcp = rcpFromRef(d_ref)); 00391 ECHO(e_rcp = null); 00392 #if defined(TEUCHOS_DEBUG) 00393 TEST_THROW(d_rcp->D_g(), DanglingReferenceError); 00394 #else 00395 TEST_NOTHROW(d_rcp.getRawPtr()); 00396 #endif 00397 } 00398 00399 00400 // rcpFromUndefRef (Can never detect dangling references) 00401 00402 00403 TEUCHOS_UNIT_TEST( RCP, rcpFromUndefRef_duplicate_rcp_nonowning_polymorphic_same_addr ) 00404 { 00405 SET_RCPNODE_TRACING(); 00406 ECHO(RCP<A> a_rcp1(new C)); 00407 ECHO(A &a_ref = *a_rcp1); 00408 ECHO(RCP<A> a_rcp2 = rcpFromUndefRef(a_ref)); 00409 ECHO(a_rcp1 = null); 00410 TEST_NOTHROW(a_rcp2.getRawPtr()); 00411 } 00412 00413 00414 // 00415 // extra data and embedded objects tests 00416 // 00417 00418 00419 TEUCHOS_UNIT_TEST( RCP, get_optional_nonconst_extra_data ) 00420 { 00421 RCP<A> a_rcp = rcp(new A); 00422 set_extra_data( as<int>(1), "blob", outArg(a_rcp) ); 00423 TEST_EQUALITY_CONST(*get_optional_nonconst_extra_data<int>(a_rcp, "blob"), as<int>(1)); 00424 } 00425 00426 00427 TEUCHOS_UNIT_TEST( RCP, getOptionalEmbeddedObj_null ) 00428 { 00429 ECHO(RCP<A> a_rcp = rcp(new A)); 00430 const Ptr<const RCP<C> > c_ptr_rcp_1 = 00431 getOptionalEmbeddedObj<A, RCP<C> >(a_rcp); 00432 TEST_EQUALITY_CONST( c_ptr_rcp_1, null ); 00433 const Ptr<RCP<C> > c_ptr_rcp_2 = 00434 getOptionalNonconstEmbeddedObj<A, RCP<C> >(a_rcp); 00435 TEST_EQUALITY_CONST( c_ptr_rcp_2, null ); 00436 } 00437 00438 00439 TEUCHOS_UNIT_TEST( RCP, getOptionalEmbeddedObj_default ) 00440 { 00441 00442 ECHO(RCP<C> c_rcp = rcp(new C)); 00443 ECHO(RCP<A> a_rcp = rcpWithEmbeddedObj(new A, c_rcp)); 00444 00445 Ptr<const RCP<C> > c_ptr_rcp_1 = 00446 getOptionalEmbeddedObj<A, RCP<C> >(a_rcp); 00447 TEST_EQUALITY_CONST( is_null(c_ptr_rcp_1), false ); 00448 TEST_EQUALITY( (*c_ptr_rcp_1).getRawPtr(), c_rcp.getRawPtr() ); 00449 TEST_EQUALITY( (*c_ptr_rcp_1)->C_g(), C_g_return ); 00450 00451 Ptr<RCP<C> > c_ptr_rcp_2 = 00452 getOptionalNonconstEmbeddedObj<A, RCP<C> >(a_rcp); 00453 TEST_EQUALITY_CONST( is_null(c_ptr_rcp_2), false ); 00454 TEST_EQUALITY( (*c_ptr_rcp_2).getRawPtr(), c_rcp.getRawPtr() ); 00455 TEST_EQUALITY( (*c_ptr_rcp_2)->C_f(), C_f_return ); 00456 00457 } 00458 00459 00460 TEUCHOS_UNIT_TEST( RCP, reset_null ) 00461 { 00462 RCP<A> a_rcp = rcp(new A); 00463 a_rcp.reset(); 00464 TEST_ASSERT(is_null(a_rcp)); 00465 } 00466 00467 00468 TEUCHOS_UNIT_TEST( RCP, reset_nonnull ) 00469 { 00470 RCP<A> a_rcp = rcp(new A); 00471 C* c_rawp = new C; 00472 a_rcp.reset(c_rawp); 00473 A* a_rawp = c_rawp; 00474 TEST_EQUALITY( a_rcp.getRawPtr(), a_rawp ); 00475 } 00476 00477 00478 TEUCHOS_UNIT_TEST( RCP, nonnull ) 00479 { 00480 ECHO(RCP<A> a_rcp = rcp(new A)); 00481 TEST_EQUALITY_CONST(is_null(a_rcp), false); 00482 TEST_EQUALITY_CONST(nonnull(a_rcp), true); 00483 ECHO(a_rcp = null); 00484 TEST_EQUALITY_CONST(is_null(a_rcp), true); 00485 TEST_EQUALITY_CONST(nonnull(a_rcp), false); 00486 } 00487 00488 00489 #ifdef HAVE_TEUCHOS_BOOST 00490 00491 00492 TEUCHOS_UNIT_TEST( shared_ptr, nonnull ) 00493 { 00494 using boost::shared_ptr; 00495 ECHO(shared_ptr<A> a_sptr(new A)); 00496 TEST_EQUALITY_CONST(is_null(a_sptr), false); 00497 TEST_EQUALITY_CONST(nonnull(a_sptr), true); 00498 ECHO(a_sptr = shared_ptr<A>()); 00499 TEST_EQUALITY_CONST(is_null(a_sptr), true); 00500 TEST_EQUALITY_CONST(nonnull(a_sptr), false); 00501 } 00502 00503 00504 #endif // HAVE_TEUCHOS_BOOST 00505 00506 00507 TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( RCP, weakDelete, T ) 00508 { 00509 00510 ECHO(RCP<T> rcp_strong = rcp(new T)); 00511 00512 TEST_EQUALITY_CONST( rcp_strong.strength(), RCP_STRONG ); 00513 TEST_EQUALITY_CONST( rcp_strong.is_null(), false ); 00514 TEST_EQUALITY_CONST( rcp_strong.strong_count(), 1 ); 00515 TEST_EQUALITY_CONST( rcp_strong.weak_count(), 0 ); 00516 TEST_EQUALITY_CONST( rcp_strong.total_count(), 1 ); 00517 00518 ECHO(RCP<T> rcp_weak1 = rcp_strong.create_weak()); 00519 00520 TEST_EQUALITY_CONST( rcp_weak1.strength(), RCP_WEAK ); 00521 TEST_EQUALITY_CONST( rcp_weak1.is_null(), false ); 00522 TEST_EQUALITY_CONST( rcp_weak1.strong_count(), 1 ); 00523 TEST_EQUALITY_CONST( rcp_weak1.weak_count(), 1 ); 00524 TEST_EQUALITY_CONST( rcp_weak1.total_count(), 2 ); 00525 00526 TEST_EQUALITY_CONST( rcp_strong.strong_count(), 1 ); 00527 TEST_EQUALITY_CONST( rcp_strong.is_null(), false ); 00528 TEST_EQUALITY_CONST( rcp_strong.weak_count(), 1 ); 00529 TEST_EQUALITY_CONST( rcp_strong.total_count(), 2 ); 00530 00531 TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_strong), true ); 00532 00533 TEST_EQUALITY( rcp_weak1.get(), rcp_weak1.getRawPtr() ); 00534 TEST_EQUALITY( rcp_weak1.get(), rcp_strong.get() ); 00535 TEST_EQUALITY( rcp_weak1.getRawPtr(), rcp_strong.getRawPtr() ); 00536 00537 ECHO(RCP<T> rcp_weak2 = rcp_weak1); 00538 00539 TEST_EQUALITY_CONST( rcp_weak2.strength(), RCP_WEAK ); 00540 TEST_EQUALITY_CONST( rcp_weak2.is_null(), false ); 00541 TEST_EQUALITY_CONST( rcp_weak2.strong_count(), 1 ); 00542 TEST_EQUALITY_CONST( rcp_weak2.weak_count(), 2 ); 00543 TEST_EQUALITY_CONST( rcp_weak2.total_count(), 3 ); 00544 00545 TEST_EQUALITY_CONST( rcp_strong.strong_count(), 1 ); 00546 TEST_EQUALITY_CONST( rcp_strong.is_null(), false ); 00547 TEST_EQUALITY_CONST( rcp_strong.weak_count(), 2 ); 00548 TEST_EQUALITY_CONST( rcp_strong.total_count(), 3 ); 00549 00550 TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_strong), true ); 00551 TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_weak2), true ); 00552 TEST_EQUALITY_CONST( rcp_weak2.shares_resource(rcp_strong), true ); 00553 00554 TEST_EQUALITY( rcp_weak2.get(), rcp_strong.get() ); 00555 TEST_EQUALITY( rcp_weak2.getRawPtr(), rcp_strong.getRawPtr() ); 00556 00557 ECHO(rcp_strong = null); // This deletes the underlying object of type T! 00558 00559 TEST_EQUALITY_CONST( rcp_strong.strength(), RCP_STRENGTH_INVALID ); 00560 TEST_EQUALITY_CONST( rcp_strong.is_null(), true ); 00561 TEST_EQUALITY_CONST( rcp_strong.count(), 0 ); 00562 TEST_EQUALITY_CONST( rcp_strong.strong_count(), 0 ); 00563 TEST_EQUALITY_CONST( rcp_strong.weak_count(), 0 ); 00564 TEST_EQUALITY_CONST( rcp_strong.total_count(), 0 ); 00565 TEST_EQUALITY_CONST( rcp_strong.is_valid_ptr(), true ); 00566 00567 TEST_EQUALITY_CONST( rcp_strong.shares_resource(rcp_weak1), false ); 00568 TEST_EQUALITY_CONST( rcp_strong.shares_resource(rcp_weak2), false ); 00569 00570 TEST_EQUALITY_CONST( rcp_weak1.has_ownership(), true ); 00571 TEST_EQUALITY_CONST( rcp_weak1.count(), 0 ); 00572 TEST_EQUALITY_CONST( rcp_weak1.strong_count(), 0 ); 00573 TEST_EQUALITY_CONST( rcp_weak1.weak_count(), 2 ); 00574 TEST_EQUALITY_CONST( rcp_weak1.total_count(), 2 ); 00575 TEST_EQUALITY_CONST( rcp_weak1.is_valid_ptr(), false ); 00576 00577 TEST_EQUALITY_CONST( rcp_weak2.has_ownership(), true ); 00578 TEST_EQUALITY_CONST( rcp_weak2.count(), 0 ); 00579 TEST_EQUALITY_CONST( rcp_weak2.strong_count(), 0 ); 00580 TEST_EQUALITY_CONST( rcp_weak2.weak_count(), 2 ); 00581 TEST_EQUALITY_CONST( rcp_weak2.total_count(), 2 ); 00582 TEST_EQUALITY_CONST( rcp_weak2.is_valid_ptr(), false ); 00583 00584 TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_weak2), true ); 00585 00586 ECHO(rcp_weak1.assert_not_null()); // Does not throw! 00587 ECHO(rcp_weak2.assert_not_null()); // Does not throw! 00588 00589 TEST_THROW( rcp_weak1.assert_valid_ptr(), DanglingReferenceError ); 00590 #ifdef TEUCHOS_DEBUG 00591 TEST_THROW( rcp_weak1.operator->(), DanglingReferenceError ); 00592 TEST_THROW( *rcp_weak1, DanglingReferenceError ); 00593 TEST_THROW( rcp_weak1.create_weak(), DanglingReferenceError ); 00594 TEST_THROW( rcp_weak1.get(), DanglingReferenceError ); 00595 TEST_THROW( rcp_weak1.getRawPtr(), DanglingReferenceError ); 00596 TEST_THROW( rcp_weak1(), DanglingReferenceError ); 00597 TEST_THROW( rcp_weak1.release(), DanglingReferenceError ); 00598 #endif // TEUCHOS_DEBUG 00599 00600 ECHO(rcp_weak1 = null); // Just deicrements weak count! 00601 00602 TEST_EQUALITY_CONST( rcp_weak1.strength(), RCP_STRENGTH_INVALID ); 00603 TEST_EQUALITY_CONST( rcp_weak1.is_null(), true ); 00604 TEST_EQUALITY_CONST( rcp_weak1.count(), 0 ); 00605 TEST_EQUALITY_CONST( rcp_weak1.strong_count(), 0 ); 00606 TEST_EQUALITY_CONST( rcp_weak1.weak_count(), 0 ); 00607 TEST_EQUALITY_CONST( rcp_weak1.total_count(), 0 ); 00608 TEST_EQUALITY_CONST( rcp_weak1.is_valid_ptr(), true ); 00609 00610 TEST_EQUALITY_CONST( rcp_weak2.has_ownership(), true ); 00611 TEST_EQUALITY_CONST( rcp_weak2.count(), 0 ); 00612 TEST_EQUALITY_CONST( rcp_weak2.strong_count(), 0 ); 00613 TEST_EQUALITY_CONST( rcp_weak2.weak_count(), 1 ); 00614 TEST_EQUALITY_CONST( rcp_weak2.total_count(), 1 ); 00615 TEST_EQUALITY_CONST( rcp_weak2.is_valid_ptr(), false ); 00616 00617 TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_weak2), false ); 00618 00619 TEST_THROW( rcp_weak2.assert_valid_ptr(), DanglingReferenceError ); 00620 #ifdef TEUCHOS_DEBUG 00621 TEST_THROW( rcp_weak2.operator->(), DanglingReferenceError ); 00622 TEST_THROW( *rcp_weak2, DanglingReferenceError ); 00623 TEST_THROW( rcp_weak2.create_weak(), DanglingReferenceError ); 00624 TEST_THROW( rcp_weak2.get(), DanglingReferenceError ); 00625 TEST_THROW( rcp_weak2.getRawPtr(), DanglingReferenceError ); 00626 TEST_THROW( rcp_weak2(), DanglingReferenceError ); 00627 TEST_THROW( rcp_weak2.release(), DanglingReferenceError ); 00628 #endif // TEUCHOS_DEBUG 00629 00630 } 00631 00632 00633 TEUCHOS_UNIT_TEST( RCP, weak_strong ) 00634 { 00635 00636 ECHO(RCP<A> rcp1(rcp(new A))); 00637 TEST_EQUALITY_CONST( rcp1.strength(), RCP_STRONG ); 00638 00639 ECHO(RCP<A> rcp2 = rcp1.create_weak()); 00640 00641 TEST_EQUALITY_CONST( rcp2.strength(), RCP_WEAK ); 00642 TEST_EQUALITY_CONST( rcp1.strong_count(), 1 ); 00643 TEST_EQUALITY_CONST( rcp1.weak_count(), 1 ); 00644 TEST_EQUALITY_CONST( rcp2.strong_count(), 1 ); 00645 TEST_EQUALITY_CONST( rcp2.weak_count(), 1 ); 00646 00647 ECHO(RCP<A> rcp3 = rcp2.create_strong()); 00648 00649 TEST_EQUALITY_CONST( rcp3.strength(), RCP_STRONG ); 00650 TEST_EQUALITY_CONST( rcp1.strong_count(), 2 ); 00651 TEST_EQUALITY_CONST( rcp1.weak_count(), 1 ); 00652 TEST_EQUALITY_CONST( rcp2.strong_count(), 2 ); 00653 TEST_EQUALITY_CONST( rcp2.weak_count(), 1 ); 00654 00655 // This will make the underlying object A gets deleted! 00656 ECHO(rcp1 = null); 00657 ECHO(rcp3 = null); 00658 00659 ECHO(rcp2 = null); // Should make the underlying node go away 00660 00661 } 00662 00663 00664 // 00665 // circularReference 00666 // 00667 00668 00669 TEUCHOS_UNIT_TEST( RCP, circularReference_a_then_c ) 00670 { 00671 00672 //TEST_EQUALITY_CONST(Teuchos::numActiveRCPNodes(), 0); 00673 00674 { 00675 00676 // Create objects a and c 00677 00678 ECHO(RCP<A> a = rcp(new A)); 00679 ECHO(RCP<C> c = rcp(new C)); 00680 00681 // Create a circular reference where 'a' owns 'c' strongly but 'c' only 00682 // owns 'a' weakly. 00683 00684 ECHO(a->set_C(c)); 00685 ECHO(c->set_A(a.create_weak())); 00686 00687 #ifdef TEUCHOS_DEBUG 00688 ECHO(c->call_A_on_delete(true)); 00689 // Here, we set 'c' to call 'a' when it is deleted which will result in an 00690 // exception being thrown in a call to delete. NOTE: It is *very* bad 00691 // practice to allow exceptions to be thrown from destructors but I am 00692 // allowing it so that I can detect such bad bahavior below! 00693 #endif 00694 00695 TEST_EQUALITY( a->call_C_f(), C_f_return ); 00696 TEST_EQUALITY( c->call_A_g(), A_g_return ); 00697 00698 // Remove 'a' first and then remove 'c'. Since 'a' is only weakly held by 00699 // 'c', this will result in 'a' being deleted right away. In this case, 00700 // if anyone tries to access 'a' after this (like 'c' in its destructor), 00701 // then an exception will get thrown in debug mode! 00702 00703 ECHO(a = null); 00704 00705 // Now, remove 'c'. In this case, since 'a' has already been deleted and 00706 // 'c' is going to try to call 'a' on its way out, this will thrown an 00707 // exception. 00708 00709 #ifdef TEUCHOS_DEBUG 00710 00711 TEST_THROW(c = null, DanglingReferenceError); 00712 // NOTE: Above, operator==(...) exhibits the 'strong' guarantee? 00713 00714 // Since an exception was thrown, the 'c' object never got deleted. 00715 // Therefore, we need to disable 'c' calling 'a' on delete and the object 00716 // will get cleaned up correctly when this function exists (I hope). 00717 ECHO(c->call_A_on_delete(false)); 00718 00719 ECHO(c = null); // All memory should be cleaned up here! 00720 00721 #endif // TEUCHOS_DEBUG 00722 00723 } 00724 00725 } 00726 00727 00728 TEUCHOS_UNIT_TEST( RCP, circularReference_c_then_a ) 00729 { 00730 00731 { 00732 00733 // Create objects a and c 00734 00735 ECHO(RCP<A> a = rcp(new A)); 00736 ECHO(RCP<C> c = rcp(new C)); 00737 00738 // Create a circular reference where 'a' owns 'c' strongly but 'c' only 00739 // owns 'a' weakly. 00740 00741 ECHO(a->set_C(c)); 00742 ECHO(c->set_A(a.create_weak())); 00743 00744 ECHO(c->call_A_on_delete(false)); 00745 // Here, we set 'c' to not call 'a' when it is deleted. It turns out that 00746 // the set of calls to delete and destructors that takes place is very 00747 // complex and in order to avoid trouble, an object that holds an RCP to 00748 // another object weakly should *never* try to call any members on the 00749 // wrapped object as it gets deleted! 00750 00751 TEST_EQUALITY( a->call_C_f(), C_f_return ); 00752 TEST_EQUALITY( c->call_A_g(), A_g_return ); 00753 00754 // Remove 'c' first and then remove 'a' implicitly at the end of the 00755 // block. Since 'c' is held strongly by 'a' and since we are keeping the 00756 // strong pointer for 'a' alive, we can call functions on 'a' all we want 00757 // with no fear of accessing dead memory. 00758 00759 ECHO(c = null); 00760 00761 TEST_EQUALITY( a->call_C_f(), C_f_return ); // C is still alive! 00762 00763 // Finally, when 'a' goes away implicitly, it will take 'c' with it. In 00764 // the complex set of nested calls that take place due to the circular 00765 // reference, everything will get cleaned up correctly. Also, if any 00766 // client code where to try to access an object as it is being deleted, an 00767 // exception will get thrown and no memory error will occur (unless an 00768 // abort(...) is called when an exception gets thrown from a destructor 00769 // when an exception is already active). 00770 00771 } 00772 00773 } 00774 00775 00776 TEUCHOS_UNIT_TEST( RCP, circularReference_self ) 00777 { 00778 { 00779 // Create one 'c' object 00780 ECHO(RCP<C> c = rcp(new C)); 00781 // Create a weak circular reference where 'c' points back to itself 00782 ECHO(c->set_A(c.create_weak())); 00783 // Now, try to set 'c' to null. 00784 ECHO(c = null); // All memory should be cleaned up here! 00785 } 00786 } 00787 00788 00789 TEUCHOS_UNIT_TEST( RCP, danglingPtr ) 00790 { 00791 ECHO(RCP<A> a_rcp = rcp(new A)); 00792 ECHO(Ptr<A> a_ptr = a_rcp()); 00793 ECHO(A *badPtr = a_rcp.getRawPtr()); 00794 ECHO(a_rcp = null); 00795 #ifdef TEUCHOS_DEBUG 00796 TEST_THROW( *a_ptr, DanglingReferenceError ); 00797 (void)badPtr; 00798 #else 00799 TEST_EQUALITY( a_ptr.getRawPtr(), badPtr ); 00800 #endif 00801 } 00802 00803 00804 #ifdef TEUCHOS_DEBUG 00805 00806 /* ToDo: Comment this back in once I have everything working 00807 00808 // Test that the RCPNode tracing machinary can detect if an owning RCPNode is 00809 // being created that would result in a double delete. 00810 TEUCHOS_UNIT_TEST( RCP, multiRcpCreateError ) 00811 { 00812 C *c_ptr = new C; 00813 #if !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING) 00814 Teuchos::setTracingActiveRCPNodes(true); 00815 #endif 00816 RCP<C> c_rcp = rcp(c_ptr); // Okay 00817 RCP<C> c_rcp2; 00818 TEST_THROW(c_rcp2 = rcp(c_ptr), DuplicateOwningRCPError); 00819 #if !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING) 00820 Teuchos::setTracingActiveRCPNodes(false); 00821 #endif 00822 // Clean up memory so no leaks and not double deletes no matter what. 00823 c_rcp.release(); 00824 c_rcp2.release(); 00825 delete c_ptr; 00826 } 00827 00828 */ 00829 00830 #endif // TEUCHOS_DEBUG 00831 00832 00833 // 00834 // invertObjectOwnership 00835 // 00836 00837 00838 RCP<C> createCAFactory() 00839 { 00840 RCP<C> c = rcp(new C); 00841 c->set_A(rcp(new A)); 00842 return c; 00843 } 00844 00845 00846 RCP<A> createACFactory() 00847 { 00848 RCP<C> c = createCAFactory(); 00849 return Teuchos::rcpWithInvertedObjOwnership(c->get_A(), c); 00850 } 00851 00852 00853 RCP<C> extractCFromA(const RCP<A> &a) 00854 { 00855 return Teuchos::getInvertedObjOwnershipParent<C>(a); 00856 } 00857 00858 00859 TEUCHOS_UNIT_TEST( RCP, invertObjectOwnership_basic ) 00860 { 00861 RCP<A> a = createACFactory(); 00862 RCP<C> c = extractCFromA(a); 00863 TEST_EQUALITY_CONST( a.strong_count(), 1 ); 00864 TEST_EQUALITY_CONST( c->get_A().strong_count(), 3 ); 00865 TEST_ASSERT( !a.shares_resource(c->get_A()) ); 00866 TEST_EQUALITY( a.getRawPtr(), c->get_A().getRawPtr() ); 00867 TEST_EQUALITY( a->A_g(), A_g_return ); 00868 TEST_EQUALITY( c->C_g(), C_g_return ); 00869 } 00870 00871 00872 // This unit test shows that you can remove the RCP in the C object 00873 // and the A object will still live on. 00874 TEUCHOS_UNIT_TEST( RCP, invertObjectOwnership_remove_A ) 00875 { 00876 RCP<A> a = createACFactory(); 00877 extractCFromA(a)->set_A(null); 00878 RCP<C> c = extractCFromA(a); 00879 TEST_EQUALITY_CONST( a.strong_count(), 1 ); 00880 TEST_EQUALITY_CONST( c->get_A(), null ); 00881 TEST_EQUALITY( a->A_g(), A_g_return ); 00882 TEST_EQUALITY( c->C_g(), C_g_return ); 00883 } 00884 00885 00886 // 00887 // createRCPWithBadDealloc 00888 // 00889 00890 00891 RCP<A> createRCPWithBadDealloc() 00892 { 00893 return rcp(new A[1]); // Will use delete but should use delete []! 00894 } 00895 00896 00897 template<typename T> 00898 class DeallocArrayDeleteExtraData { 00899 public: 00900 static RCP<DeallocArrayDeleteExtraData<T> > create(T *ptr) 00901 { return rcp(new DeallocArrayDeleteExtraData(ptr)); } 00902 ~DeallocArrayDeleteExtraData() { delete [] ptr_; } 00903 private: 00904 T *ptr_; 00905 DeallocArrayDeleteExtraData(T *ptr) : ptr_(ptr) {} 00906 // Not defined! 00907 DeallocArrayDeleteExtraData(); 00908 DeallocArrayDeleteExtraData(const DeallocArrayDeleteExtraData&); 00909 DeallocArrayDeleteExtraData& operator=(const DeallocArrayDeleteExtraData&); 00910 }; 00911 00912 00913 // This unit test shows how you can use extra data to fix a bad deallocation 00914 // policy 00915 TEUCHOS_UNIT_TEST( RCP, Fix_createRCPWithBadDealloc ) 00916 { 00917 using Teuchos::inOutArg; 00918 using Teuchos::set_extra_data; 00919 // Create object with bad deallocator 00920 RCP<A> a = createRCPWithBadDealloc(); 00921 TEST_ASSERT(nonnull(a)); 00922 // Disable default (incorrect) dealloc and set a new deallocation policy as extra data! 00923 a.release(); 00924 set_extra_data( DeallocArrayDeleteExtraData<A>::create(a.getRawPtr()), "dealloc", 00925 inOutArg(a)); 00926 } 00927 00928 00929 // 00930 // Template Instantiations 00931 // 00932 00933 00934 #ifdef TEUCHOS_DEBUG 00935 00936 # define DEBUG_UNIT_TEST_GROUP( T ) \ 00937 00938 #else 00939 00940 # define DEBUG_UNIT_TEST_GROUP( T ) 00941 00942 #endif 00943 00944 00945 #define UNIT_TEST_GROUP( T ) \ 00946 TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( RCP, weakDelete, T ) \ 00947 DEBUG_UNIT_TEST_GROUP(T) 00948 00949 00950 UNIT_TEST_GROUP(A) 00951 UNIT_TEST_GROUP(C) 00952 UNIT_TEST_GROUP(D) 00953 UNIT_TEST_GROUP(E) 00954 00955 00956 } // namespace
1.7.4