| /*************************************************************************** |
| * |
| * 20.autoptr.cpp - test exercising [lib.auto.ptr] |
| * |
| * $Id$ |
| * |
| *************************************************************************** |
| * |
| * Copyright 2006 The Apache Software Foundation or its licensors, |
| * as applicable. |
| * |
| * Copyright 2000-2006 Rogue Wave Software. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| **************************************************************************/ |
| |
| #include <rw/_defs.h> |
| |
| #if defined (__IBMCPP__) && !defined (_RWSTD_NO_IMPLICIT_INCLUSION) |
| // disable implicit inclusion to work around |
| // a limitation in IBM VisualAge 5.0.2.0 (see PR #26959) |
| # define _RWSTD_NO_IMPLICIT_INCLUSION |
| #endif |
| |
| #include <memory> |
| |
| /**************************************************************************/ |
| |
| #ifndef _RWSTD_EXPLICIT_INSTANTIATION |
| |
| // explicitly instantiate |
| |
| # if !defined (_RWSTD_NO_NAMESPACE) && !defined (_RWSTD_NO_HONOR_STD) |
| |
| // verify that names are declared [only[ in namespace std |
| |
| # define TEST_CLASS_DEF(name, Tparam) \ |
| template class std::name Tparam \ |
| /* void name (void *name) */ |
| |
| # else // if defined (_RWSTD_NO_NAMESPACE) || defined (_RWSTD_NO_HONOR_STD) |
| |
| // verify that names do not collide with function argument names |
| |
| # define TEST_CLASS_DEF(name, Tparam) \ |
| template class std::name Tparam; \ |
| void foo (void *name) |
| |
| # endif // !_RWSTD_NO_NAMESPACE && !_RWSTD_NO_HONOR_STD |
| |
| #else // if defined (_RWSTD_EXPLICIT_INSTANTIATION) |
| |
| // classes will implicitly instantiated below |
| |
| # if !defined (_RWSTD_NO_NAMESPACE) && !defined (_RWSTD_NO_HONOR_STD) |
| |
| // verify that names are declared [only] in namespace std |
| |
| # define TEST_CLASS_DEF(name, ignore) void name (void *name) |
| |
| # else // if defined (_RWSTD_NO_NAMESPACE) || defined (_RWSTD_NO_HONOR_STD) |
| |
| # define TEST_CLASS_DEF(name, ignore) void foo (void *name) |
| |
| # endif // !_RWSTD_NO_NAMESPACE && !_RWSTD_NO_HONOR_STD |
| |
| #endif // _RWSTD_EXPLICIT_INSTANTIATION |
| |
| |
| // auto_ptr_ref instantiated first to prevent bogus MSVC 6.0 warning C4660: |
| // template-class specialization 'auto_ptr_ref<int>' is already instantiated |
| // follows lwg issue 127 |
| TEST_CLASS_DEF (auto_ptr_ref, <int>); |
| |
| TEST_CLASS_DEF (auto_ptr, <int>); |
| |
| /**************************************************************************/ |
| |
| #include <cmdopt.h> // for rw_enabled() |
| #include <driver.h> // for rw_assert(), rw_test(), ... |
| |
| /**************************************************************************/ |
| |
| struct Base |
| { |
| int i_; // unique object id |
| |
| static int cnt_; // object counter |
| static int gen_; // unique id generator |
| |
| Base (): i_ (gen_++) { ++cnt_; } |
| |
| ~Base () { |
| --cnt_; |
| } |
| |
| static void sink (std::auto_ptr<Base>) { } |
| }; |
| |
| int Base::cnt_; // Base object counter |
| int Base::gen_; // Base unique id generator |
| |
| struct Derived: Base |
| { |
| static std::auto_ptr<Derived> source () { |
| return std::auto_ptr<Derived> (); |
| } |
| |
| static void sink (std::auto_ptr<Derived>) { } |
| }; |
| |
| |
| // helpers to verify that each class' ctor is explicit |
| // not defined since they must not be referenced if test is successful |
| void is_explicit (const std::auto_ptr<Base>&); |
| |
| struct has_implicit_ctor |
| { |
| // NOT explicit |
| #ifndef _RWSTD_NO_NATIVE_BOOL |
| |
| has_implicit_ctor (bool*) { } |
| |
| #endif // _RWSTD_NO_NATIVE_BOOL |
| |
| has_implicit_ctor (char*) { } |
| has_implicit_ctor (int*) { } |
| has_implicit_ctor (double*) { } |
| has_implicit_ctor (void**) { } |
| has_implicit_ctor (Base*) { } |
| }; |
| |
| void is_explicit (const has_implicit_ctor&) { } |
| |
| |
| template <class T> |
| void test_auto_ptr (T*, const char *tname) |
| { |
| rw_info (0, 0, 0, "std::auto_ptr<%s>", tname); |
| |
| if (!rw_enabled (tname)) { |
| rw_note (0, 0, __LINE__, "auto_ptr<%s> test disabled", tname); |
| return; |
| } |
| |
| // exercise 20.4.5, p2 - auto_ptr<> interface |
| |
| typedef _TYPENAME std::auto_ptr<T>::element_type element_type; |
| |
| // verify that element_type is the same as T |
| element_type *elem = (T*)0; |
| |
| // verify that default ctor is explicit |
| is_explicit (elem); |
| |
| |
| // verify that a member function is accessible and has the appropriate |
| // signature, including return type and exception specification |
| #define FUN(result, T, name, arg_list) do { \ |
| result (std::auto_ptr<T>::*pf) arg_list = &std::auto_ptr<T>::name; \ |
| _RWSTD_UNUSED (pf); \ |
| } while (0) |
| |
| #if !defined (__HP_aCC) || _RWSTD_HP_aCC_MAJOR > 5 |
| |
| // working around a bug in aCC (see PR #24430) |
| FUN (std::auto_ptr<T>&, T, operator=, (std::auto_ptr<T>&) _PTR_THROWS(())); |
| |
| #endif // HP aCC > 5 |
| |
| FUN (T&, T, operator*, () const _PTR_THROWS (())); |
| |
| #ifndef _RWSTD_NO_NONCLASS_ARROW_RETURN |
| |
| FUN (T*, T, operator->, () const _PTR_THROWS (())); |
| |
| #endif // _RWSTD_NO_NONCLASS_ARROW_RETURN |
| |
| FUN (T*, T, get, () const _PTR_THROWS (())); |
| FUN (T*, T, release, () _PTR_THROWS (())); |
| FUN (void, T, reset, (T*) _PTR_THROWS (())); |
| |
| #ifndef _RWSTD_NO_MEMBER_TEMPLATES |
| |
| # if !defined(__GNUG__) || __GNUG__ > 3 || __GNUG__ == 3 && __GNUC_MINOR__ > 2 |
| |
| // g++ 2.95.2 and HP aCC can't take the address of a template member |
| |
| # if !defined (__HP_aCC) || _RWSTD_HP_aCC_MAJOR > 5 |
| |
| // SunPro incorrectly warns here (see PR #27276) |
| FUN (std::auto_ptr<Base>&, Base, |
| operator=, (std::auto_ptr<Derived>&) _PTR_THROWS (())); |
| |
| // SunPro 5.4 can't decide between a ctor template |
| // and a conversion operator (see PR #24476) |
| # if !defined (__SUNPRO_CC) || __SUNPRO_CC > 0x540 |
| |
| FUN (std::auto_ptr_ref<Base>, Derived, |
| operator std::auto_ptr_ref<Base>, () _PTR_THROWS (())); |
| |
| FUN (std::auto_ptr<Base>, Derived, |
| operator std::auto_ptr<Base>, () _PTR_THROWS (())); |
| |
| # endif // SunPro > 5.4 |
| |
| # endif // HP aCC > 5 |
| |
| # endif // gcc > 3.2 |
| |
| #endif // _RWSTD_NO_MEMBER_TEMPLATES |
| |
| rw_info (0, 0, 0, "[lib.auto.ptr.cons]"); |
| |
| T *pt = new T; |
| |
| // 20.4.5.1, p1 |
| std::auto_ptr<T> ap1 (pt); |
| rw_assert (pt == ap1.get (), 0, __LINE__, |
| "auto_ptr<%s>::auto_ptr (%1$s*)", tname); |
| |
| // 20.4.5.1, p2 |
| std::auto_ptr<T> ap2 (ap1); |
| rw_assert (0 == ap1.get (), 0, __LINE__, |
| "auto_ptr<%s>::auto_ptr (auto_ptr&", tname); |
| rw_assert (pt == ap2.get (), 0, __LINE__, |
| "auto_ptr<%s>::auto_ptr (auto_ptr&)", tname); |
| |
| // 20.4.5.1, p7, 8, 9 |
| ap1 = ap2; |
| rw_assert (0 == ap2.get (), 0, __LINE__, |
| "auto_ptr<%s>::operator= (auto_ptr&)", tname); |
| rw_assert (pt == ap1.get (), 0, __LINE__, |
| "auto_ptr<%s>::operator= (auto_ptr&)", tname); |
| |
| |
| rw_info (0, 0, 0, "[lib.auto.ptr.members]"); |
| |
| // 20.4.5.2, p2 |
| rw_assert (*ap1.get () == ap1.operator*(), 0, __LINE__, |
| "auto_ptr<%s>::operator*()", tname); |
| |
| // 20.4.5.2, p3 |
| rw_assert (ap1.get () == ap1.operator->(), 0, __LINE__, |
| "auto_ptr<%s>::operator->()", tname); |
| |
| // 20.4.5.2, p4 |
| rw_assert (pt == ap1.get (), 0, __LINE__, |
| "auto_ptr<%s>::get ()", tname); |
| |
| // 20.4.5.2, p5, 6 |
| rw_assert (pt == ap1.release () && 0 == ap1.get (), 0, __LINE__, |
| "auto_ptr<%s>::release ()", tname); |
| |
| |
| // 20.4.5.2, p7 |
| ap1.reset (pt); |
| rw_assert (pt == ap1.get (), 0, __LINE__, |
| "auto_ptr<%s>::reset ()", tname); |
| } |
| |
| /**************************************************************************/ |
| |
| static void |
| test_auto_ptr_void () |
| { |
| // note that specializing auto_ptr on void is undefined |
| // due to 17.4.3.6, p2; this is an extension of this |
| // implementation |
| rw_info (0, 0, 0, "std::auto_ptr<void> [extension]"); |
| |
| std::auto_ptr<void> ap1; |
| std::auto_ptr<void> ap2 ((void*)0); |
| std::auto_ptr<void> ap3 (ap2); |
| |
| ap1 = ap1; |
| ap1.operator= (ap1); |
| |
| #ifndef _RWSTD_NO_MEMBER_TEMPLATES |
| |
| ap1.operator=<void>(ap1); |
| |
| std::auto_ptr<int> ap4; |
| ap1 = ap4; |
| ap1.operator= (ap4); |
| ap1.operator=<int>(ap4); |
| |
| #endif // _RWSTD_NO_MEMBER_TEMPLATES |
| |
| // operator*() cannot be instantiated |
| |
| void* pv; |
| |
| pv = ap1.operator->(); |
| pv = ap1.get (); |
| pv = ap1.release (); |
| |
| ap1.reset (); |
| ap1.reset (pv); |
| |
| #ifndef _RWSTD_NO_MEMBER_TEMPLATES |
| |
| const std::auto_ptr_ref<void> ar = ap1.operator std::auto_ptr_ref<void>(); |
| const std::auto_ptr<void> ap5 = ap1.operator std::auto_ptr<void>(); |
| |
| _RWSTD_UNUSED (ar); |
| _RWSTD_UNUSED (ap5); |
| |
| #endif // _RWSTD_NO_MEMBER_TEMPLATES |
| |
| } |
| |
| /**************************************************************************/ |
| |
| #ifndef _RWSTD_NO_MEMBER_TEMPLATES |
| |
| // exercise 20.4.5.4 |
| static std::auto_ptr<Derived> |
| test_auto_ptr_conversions () |
| { |
| rw_info (0, 0, 0, "[lib.auto.ptr.conv]"); |
| |
| // 20.4.5.1, p4, 5, 6 |
| Derived *pd = new Derived; |
| std::auto_ptr<Derived> ap1 (pd); |
| rw_assert (pd == ap1.get (), 0, __LINE__, |
| "auto_ptr::auto_ptr ()"); |
| |
| std::auto_ptr<Base> ap2 (ap1); |
| |
| rw_assert (0 == ap1.get (), 0, __LINE__, |
| "auto_ptr<Base>::auto_ptr(auto_ptr<Derived>&)"); |
| rw_assert (_RWSTD_STATIC_CAST (Base*, pd) == ap2.get (), 0, __LINE__, |
| "auto_ptr<Base>::auto_ptr(auto_ptr<Derived>&)"); |
| |
| ap2.reset (pd); |
| |
| // 20.4.5.2, p7 - must not delete owning pointer |
| ap2.reset (pd); |
| rw_assert (pd == ap2.get (), 0, __LINE__, "auto_ptr::reset ()"); |
| |
| pd = new Derived; |
| ap2.reset (pd); // must delete owning pointer |
| rw_assert (pd == ap2.get (), 0, __LINE__, "auto_ptr::reset ()"); |
| |
| // 20.4.5.3, p1, 2, 3 - creates an auto_ptr_ref |
| pd = new Derived; |
| std::auto_ptr<Base> ap3 = |
| std::auto_ptr<Base>(std::auto_ptr<Derived>(pd)); |
| |
| rw_assert ((Base*)pd == ap3.get (), 0, __LINE__, |
| "auto_ptr<>::auto_ptr(std::auto_ptr_ref)"); |
| |
| #if !defined (__HP_aCC) || _RWSTD_HP_aCC_MAJOR > 5 |
| |
| pd = new Derived; |
| std::auto_ptr<Derived> ap4 (pd); |
| ap3 = std::auto_ptr<Base> (ap4); |
| |
| rw_assert (0 == ap4.get () && (Base*)pd == ap3.get (), 0, __LINE__, |
| "auto_ptr<>::operator auto_ptr<>()"); |
| |
| #endif // HP aCC > 5 |
| |
| { |
| // see CWG issue 84 for some background on the sequence below |
| // http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#84 |
| |
| std::auto_ptr<Derived> pd1 (Derived::source ()); |
| std::auto_ptr<Derived> pd2 (pd1); |
| |
| #if !defined (__HP_aCC) || _RWSTD_HP_aCC_MAJOR > 5 |
| |
| Derived::sink (Derived::source ()); |
| |
| #endif // HP aCC > 5 |
| |
| pd1 = pd2; |
| pd1 = Derived::source(); |
| std::auto_ptr<Base> pb1 (Derived::source ()); |
| std::auto_ptr<Base> pb2 (pd1); |
| |
| // conversion sequence: |
| // 1. auto_ptr<Derived>::operator auto_ptr<Base>() [UDC] |
| // 2. auto_ptr<Base>::operator auto_ptr_ref<Base>() [UDC] |
| // 3. auto_ptr<Base>(auto_ptr_ref<Base>) [UDC] |
| |
| // since the conversion sequence involves more than one UDC |
| // (User-Defined Conversion), it is illegal |
| // Base::sink (Derived::source ()); |
| |
| pb1 = pd2; |
| pb1 = Derived::source (); |
| |
| return pd1; |
| } |
| } |
| |
| #endif // _RWSTD_NO_MEMBER_TEMPLATES |
| |
| /**************************************************************************/ |
| |
| static int rw_opt_no_conversions; // for --no-conversions |
| |
| |
| static int |
| run_test (int, char**) |
| { |
| |
| #ifndef _RWSTD_NO_NATIVE_BOOL |
| |
| test_auto_ptr ((bool*)0, "bool"); |
| |
| #endif // _RWSTD_NO_NATIVE_BOOL |
| |
| test_auto_ptr ((char*)0, "char"); |
| test_auto_ptr ((int*)0, "int"); |
| test_auto_ptr ((double*)0, "double"); |
| test_auto_ptr ((void**)0, "void*"); |
| |
| #ifndef _RWSTD_NO_MEMBER_TEMPLATES |
| |
| int count = Base::cnt_; |
| |
| // exercise 20.4.5.4 |
| if (rw_opt_no_conversions) |
| rw_note (0, 0, 0, "conversions test disabled"); |
| else |
| test_auto_ptr_conversions (); |
| |
| // verify that no objects leaked |
| rw_assert (count == Base::cnt_, 0, __LINE__, |
| "autoptr leaked %d objects", Base::cnt_ - count); |
| |
| #endif // _RWSTD_NO_MEMBER_TEMPLATES |
| |
| if (!rw_enabled ("void")) |
| rw_note (0, 0, 0, "auto_ptr<void> test disabled"); |
| else |
| test_auto_ptr_void (); |
| |
| return 0; |
| } |
| |
| /**************************************************************************/ |
| |
| int main (int argc, char *argv[]) |
| { |
| return rw_test (argc, argv, __FILE__, |
| "lib.auto.ptr", |
| 0 /* no comment */, |
| run_test, |
| "|-no-conversions#", |
| &rw_opt_no_conversions, |
| (void*)0 /* sentinel */); |
| } |