Teuchos Package Browser (Single Doxygen Collection) Version of the Day
RCP_UnitTests.cpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines