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