483 lines
14 KiB
C++
483 lines
14 KiB
C++
/***************************************************************************
|
|
*
|
|
* 20.autoptr.cpp - test exercising [lib.auto.ptr]
|
|
*
|
|
* $Id: 20.auto.ptr.cpp 596356 2007-11-19 16:23:21Z faridz $
|
|
*
|
|
***************************************************************************
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you 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.
|
|
*
|
|
* Copyright 2000-2007 Rogue Wave Software, Inc.
|
|
*
|
|
**************************************************************************/
|
|
|
|
#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
|
|
|
|
# if !defined (_MSC_VER) || _MSC_VER > 1310 || defined (__INTEL_COMPILER)
|
|
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 // MSVC > 7.1
|
|
|
|
# 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
|
|
|
|
# if !defined (__HP_aCC) || 6 <= _RWSTD_HP_aCC_MAJOR
|
|
|
|
// working around an HP aCC 3 and 5 bug (STDCXX-655)
|
|
|
|
ap1.operator=<void>(ap1);
|
|
|
|
# endif // !HP aCC or HP aCC 6 and better
|
|
|
|
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
|
|
|
|
# if !defined (__HP_aCC) || 6 <= _RWSTD_HP_aCC_MAJOR
|
|
|
|
// working around an HP aCC 3 and 5 bug (STDCXX-656)
|
|
|
|
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 // !HP aCC or HP aCC 6 and better
|
|
#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 */);
|
|
}
|