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