da502b99be
git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@761 7ec92016-0320-0410-acc4-a06ded1c099a
760 lines
23 KiB
C++
760 lines
23 KiB
C++
/** @file DefaultAlloc.cpp Tests compiler compliance when using the new and
|
|
delete operators.
|
|
|
|
@author Rich Sposato (original author)
|
|
|
|
@par Purpose of Program
|
|
This program tests how well C++ compilers comply with the ISO C++ Standard in
|
|
implementing new, new [], delete, and delete [] operators. The program should
|
|
identify each known way in which a C++ compiler can fail to comply. It
|
|
provides versions of each new, new[], delete, and delete [] operators that
|
|
classes typically overload. These functions have the same signatures as
|
|
those in the Loki project, and the same as those enumerated in section 18 of
|
|
the ISO C++ Standard.
|
|
|
|
@par Running the Program
|
|
If the programs fails to compile, or crashes when executed, the compiler does
|
|
not comply with the ISO C++ Standard. As the program runs, it should:
|
|
- identify your compiler,
|
|
- execute each version of the new, new[], delete, and delete [] operators,
|
|
- determine if compiler provides correct behavior when exceptions are thrown,
|
|
- determine if correct operators were called for each appropriate situation,
|
|
- and determine if the correct parameters were provided to each function.
|
|
|
|
@par License
|
|
This file is released under the MIT License - like the rest of Loki. You
|
|
may use it and modify it as you wish - except that the entire set of
|
|
documentation commentary at the top of this file shall remain intact.
|
|
|
|
@par Connection to Loki
|
|
This file is provided as part of the Loki project - but does not depend upon
|
|
any other files in Loki. It was made for Loki by Rich Sposato to determine
|
|
which compilers can safely use Loki's Small-Object Allocator. During his
|
|
work on Loki, Rich noticed that some compilers did not provide the correct
|
|
values to the allocation / deallocation operators, or worse, called the wrong
|
|
operator. Rather than make several variations of allocator functions to work
|
|
around areas of non-compliance, Rich decided to write a program that exposes
|
|
which compilers do not comply with the ISO C++ Standard. It is recommended
|
|
that you execute this program before incorporating Loki's Small-Object
|
|
Allocator from your source code. Hence, this program is a "crash test dummy"
|
|
for how well your compiler can handle Loki.
|
|
*/
|
|
|
|
// $Id$
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include <iostream>
|
|
#include <new>
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
using namespace std;
|
|
|
|
|
|
/** @par Array Overhead
|
|
Most compilers require a few extra bytes when allocating arrays via the new []
|
|
operators. The overhead is needed to keep track of how many objects are in
|
|
the array and how many bytes were allocated. The overhead often exists as 4
|
|
extra bytes at the start of the array.
|
|
*/
|
|
static const unsigned int ArrayOverhead = 4;
|
|
static const unsigned int ArrayCount = 1000;
|
|
|
|
static bool s_verbose = false;
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class EmptyThing { };
|
|
|
|
class BadBee : public std::exception
|
|
{
|
|
public:
|
|
BadBee( void ) : m_message( "Unknown exception." ) {}
|
|
BadBee( const char * m ) : m_message( m ) {}
|
|
virtual ~BadBee( void ) throw() {}
|
|
virtual const char* what() const throw() { return m_message; }
|
|
private:
|
|
const char * m_message;
|
|
};
|
|
|
|
class Bee
|
|
{
|
|
public:
|
|
|
|
/// Enumerates all the new and delete operators.
|
|
enum OperatorName
|
|
{
|
|
Unknown,
|
|
NewScalarThrow,
|
|
NewScalarNoThrow,
|
|
NewScalarPlacement,
|
|
DeleteScalarWithSize,
|
|
DeleteScalarNoThrow,
|
|
DeleteScalarPlacement,
|
|
NewArrayThrow,
|
|
NewArrayNoThrow,
|
|
NewArrayPlacement,
|
|
DeleteArrayWithSize,
|
|
DeleteArrayNoThrow,
|
|
DeleteArrayPlacement,
|
|
};
|
|
|
|
/// Provides textual name for all new and delete operators.
|
|
static const char * Name( OperatorName type )
|
|
{
|
|
switch ( type )
|
|
{
|
|
case NewScalarThrow:
|
|
return "scalar throwing new operator";
|
|
case NewScalarNoThrow:
|
|
return "scalar nothrow new operator";
|
|
case NewScalarPlacement:
|
|
return "scalar placement new operator";
|
|
case DeleteScalarWithSize:
|
|
return "scalar delete operator with size";
|
|
case DeleteScalarNoThrow:
|
|
return "scalar nothrow delete operator";
|
|
case DeleteScalarPlacement:
|
|
return "scalar placement delete operator";
|
|
case NewArrayThrow:
|
|
return "array throwing new operator";
|
|
case NewArrayNoThrow:
|
|
return "array nothrow new operator";
|
|
case NewArrayPlacement:
|
|
return "array placement new operator";
|
|
case DeleteArrayWithSize:
|
|
return "array delete operator with size";
|
|
case DeleteArrayNoThrow:
|
|
return "array nothrow delete operator";
|
|
case DeleteArrayPlacement:
|
|
return "array placement delete operator";
|
|
}
|
|
return "Unknown";
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
/// @note MSVC complains about non-empty exception specification lists.
|
|
static void * operator new ( std::size_t size )
|
|
#else
|
|
static void * operator new ( std::size_t size ) throw ( std::bad_alloc )
|
|
#endif
|
|
{
|
|
CheckCallType( NewScalarThrow, "new" );
|
|
void * place = ::operator new( size );
|
|
if ( s_verbose )
|
|
cout << "static void * operator new ( std::size_t size ) throw ( std::bad_alloc )" << endl
|
|
<< "\tsize = " << size << endl;
|
|
cout << endl;
|
|
return place;
|
|
}
|
|
|
|
static void * operator new ( std::size_t size, const std::nothrow_t & nt ) throw ()
|
|
{
|
|
s_triedNoThrowNew = true;
|
|
CheckCallType( NewScalarNoThrow, "new" );
|
|
void * place = ::operator new( size, nt );
|
|
if ( s_verbose )
|
|
cout << "static void * operator new ( std::size_t size," << endl
|
|
<< "\tconst std::nothrow_t & nt ) throw ()" << endl
|
|
<< "\tsize = " << size << endl;
|
|
cout << endl;
|
|
return place;
|
|
}
|
|
|
|
static void * operator new ( std::size_t size, void * place )
|
|
{
|
|
void * place2 = ::operator new( size, place );
|
|
CheckCallType( NewScalarPlacement, "new" );
|
|
if ( s_verbose )
|
|
cout << "static void * operator new ( std::size_t size, void * place )" << endl
|
|
<< "\tsize = " << size << endl
|
|
<< "\tplace = " << place << endl
|
|
<< "\treturn = " << place2 << endl;
|
|
cout << endl;
|
|
return place2;
|
|
}
|
|
|
|
/** @note This version of delete [] is commented out since the C++ Standard
|
|
requires compilers to use the version of delete [] with the size parameter
|
|
if that one is available and this one is not.
|
|
*/
|
|
// static void operator delete ( void * place ) throw ()
|
|
// {
|
|
// CheckCallType( DeleteScalarNoSize, "delete" );
|
|
// cout << "scalar delete operator" << endl;
|
|
// if ( s_verbose )
|
|
// cout << "static void operator delete ( void * place ) throw ()" << endl
|
|
// << "\tplace = " << place << endl;
|
|
// cout << endl;
|
|
// ::operator delete( place );
|
|
// }
|
|
|
|
static void operator delete ( void * place, std::size_t size ) throw ()
|
|
{
|
|
CheckCallType( DeleteScalarWithSize, "delete" );
|
|
if ( s_verbose )
|
|
cout << "static void operator delete ( void * place, std::size_t size ) throw ()" << endl
|
|
<< "\tplace = " << place << endl
|
|
<< "\tsize = " << size << endl;
|
|
cout << endl;
|
|
::operator delete( place );
|
|
}
|
|
|
|
static void operator delete ( void * place, const std::nothrow_t & nt ) throw()
|
|
{
|
|
CheckCallType( DeleteScalarNoThrow, "delete" );
|
|
if ( s_verbose )
|
|
cout << "static void operator delete ( void * place," << endl
|
|
<< "\tconst std::nothrow_t & nt ) throw()" << endl
|
|
<< "\tplace = " << place << endl;
|
|
cout << endl;
|
|
::operator delete( place, nt );
|
|
}
|
|
|
|
static void operator delete ( void * place1, void * place2 )
|
|
{
|
|
CheckCallType( DeleteScalarPlacement, "delete" );
|
|
if ( s_verbose )
|
|
cout << "static void operator delete ( void * place1, void * place2 )" << endl
|
|
<< "\tplace1 = " << place1 << endl
|
|
<< "\tplace2 = " << place2 << endl;
|
|
cout << endl;
|
|
::operator delete( place1, place2 );
|
|
}
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
/// @note MSVC complains about non-empty exception specification lists.
|
|
static void * operator new [] ( std::size_t size )
|
|
#else
|
|
static void * operator new [] ( std::size_t size ) throw ( std::bad_alloc )
|
|
#endif
|
|
{
|
|
s_newArraySize = size;
|
|
CheckCallType( NewArrayThrow, "new []" );
|
|
void * place = ::operator new [] ( size );
|
|
if ( s_verbose )
|
|
cout << "static void * operator new [] ( std::size_t size ) throw ( std::bad_alloc )" << endl
|
|
<< "\tsize = " << size << endl;
|
|
cout << endl;
|
|
return place;
|
|
}
|
|
|
|
static void * operator new [] ( std::size_t size, const std::nothrow_t & nt ) throw ()
|
|
{
|
|
s_triedNoThrowNew = true;
|
|
s_newArraySize = size;
|
|
CheckCallType( NewArrayNoThrow, "new []" );
|
|
void * place = ::operator new [] ( size, nt );
|
|
if ( s_verbose )
|
|
cout << "static void * operator new [] ( std::size_t size," << endl
|
|
<< "\tconst std::nothrow_t & nt ) throw ()" << endl
|
|
<< "\tsize = " << size << endl;
|
|
cout << endl;
|
|
return place;
|
|
}
|
|
|
|
static void * operator new [] ( std::size_t size, void * place )
|
|
{
|
|
CheckCallType( NewArrayPlacement, "new []" );
|
|
void * place2 = ::operator new [] ( size, place );
|
|
if ( s_verbose )
|
|
cout << "static void * operator new [] ( std::size_t size, void * place )" << endl
|
|
<< "\tsize = " << size << endl
|
|
<< "\tplace = " << place << endl
|
|
<< "\treturn = " << place2 << endl;
|
|
cout << endl;
|
|
return place2;
|
|
}
|
|
|
|
/** @note This version of delete [] is commented out since the C++ Standard
|
|
requires compilers to use the version of delete [] with the size parameter
|
|
if that one is available and this one is not.
|
|
*/
|
|
// static void operator delete [] ( void * place ) throw ()
|
|
// {
|
|
// CheckCallType( DeleteArrayNoSize, "delete []" );
|
|
// if ( s_verbose )
|
|
// cout << "static void operator delete [] ( void * place ) throw ()" << endl
|
|
// << "\tplace = " << place << endl;
|
|
// cout << endl;
|
|
// ::operator delete [] ( place );
|
|
// }
|
|
|
|
static void operator delete [] ( void * place, std::size_t size ) throw ()
|
|
{
|
|
s_deleteArraySize = size;
|
|
CheckCallType( DeleteArrayWithSize, "delete []" );
|
|
if ( s_verbose )
|
|
cout << "static void operator delete [] ( void * place, std::size_t size ) throw ()" << endl
|
|
<< "\tplace = " << place << endl
|
|
<< "\tsize = " << size << endl;
|
|
if ( s_newArraySize != size )
|
|
{
|
|
cout << "\tERROR: The size parameter should be: " << s_newArraySize << '!' << endl;
|
|
s_errorCount++;
|
|
}
|
|
cout << endl;
|
|
::operator delete [] ( place );
|
|
}
|
|
|
|
static void operator delete [] ( void * place, const std::nothrow_t & nt ) throw()
|
|
{
|
|
CheckCallType( DeleteArrayNoThrow, "delete []" );
|
|
if ( s_verbose )
|
|
cout << "static void operator delete [] ( void * place," << endl
|
|
<< "\tconst std::nothrow_t & nt ) throw()" << endl
|
|
<< "\tplace = " << place << endl;
|
|
cout << endl;
|
|
::operator delete [] ( place, nt );
|
|
}
|
|
|
|
static void operator delete [] ( void * place1, void * place2 )
|
|
{
|
|
CheckCallType( DeleteArrayPlacement, "delete []" );
|
|
if ( s_verbose )
|
|
cout << "static void operator delete [] ( void * place1, void * place2 )" << endl
|
|
<< "\tplace1 = " << place1 << endl
|
|
<< "\tplace2 = " << place2 << endl;
|
|
cout << endl;
|
|
::operator delete [] ( place1, place2 );
|
|
}
|
|
|
|
static void OutputArraySizeInfo( void );
|
|
|
|
inline static void Clear( void )
|
|
{
|
|
s_newArraySize = 0;
|
|
s_deleteArraySize = 0;
|
|
}
|
|
|
|
inline static void SetConstructorToThrow( bool b ) { s_throw = b; }
|
|
|
|
inline static bool WillConstructorThrow( void ) { return s_throw; }
|
|
|
|
Bee( void ) : m_legs( 6 )
|
|
{
|
|
if ( s_throw )
|
|
{
|
|
s_expectedCall = ( NewArrayNoThrow == s_expectedCall ) ?
|
|
DeleteArrayNoThrow : DeleteScalarNoThrow;
|
|
throw BadBee( "Bee died before it hatched." );
|
|
}
|
|
}
|
|
|
|
~Bee( void ) {}
|
|
|
|
inline static unsigned int GetErrorCount( void ) { return s_errorCount; }
|
|
inline static void IncrementErrorCount( void ) { ++s_errorCount; }
|
|
|
|
static OperatorName s_expectedCall;
|
|
|
|
private:
|
|
static std::size_t s_newArraySize;
|
|
static std::size_t s_deleteArraySize;
|
|
static unsigned int s_errorCount;
|
|
static bool s_triedNoThrowNew;
|
|
static bool s_throw;
|
|
|
|
static void CheckCallType( OperatorName actual, const char * name )
|
|
{
|
|
cout << Name( actual ) << endl;
|
|
if ( s_expectedCall != actual )
|
|
{
|
|
s_errorCount++;
|
|
cout << "\tERROR! The wrong " << name << " operator was called!" << endl
|
|
<< "\tExpected " << Name( s_expectedCall ) << " instead!" << endl;
|
|
}
|
|
}
|
|
|
|
unsigned int m_legs;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
Bee::OperatorName Bee::s_expectedCall = Bee::Unknown;
|
|
std::size_t Bee::s_newArraySize = 0;
|
|
std::size_t Bee::s_deleteArraySize = 0;
|
|
unsigned int Bee::s_errorCount = 0;
|
|
bool Bee::s_triedNoThrowNew = false;
|
|
bool Bee::s_throw = false;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void Bee::OutputArraySizeInfo( void )
|
|
{
|
|
cout << endl;
|
|
if ( ( 0 == s_newArraySize ) || ( 0 == s_deleteArraySize ) )
|
|
cout << "I do not have sufficient information to know if your compiler complies" << endl
|
|
<< "with Section 12.5/5 of the C++ Standard. You should not use Loki to" << endl
|
|
<< "allocate arrays. Please do not #define LOKI_SMALL_OBJECT_USE_NEW_ARRAY." << endl;
|
|
else if ( s_newArraySize == s_deleteArraySize )
|
|
cout << "Your compiler provides correct value for delete [] operator. You may use" << endl
|
|
<< "Loki to allocate arrays via #define LOKI_SMALL_OBJECT_USE_NEW_ARRAY. If" << endl
|
|
<< "you do, please run the SmallObjBench tests to see if Loki is faster or" << endl
|
|
<< "slower at allocating arrays than the default allocator." << endl
|
|
<< endl;
|
|
else
|
|
cout << "Your compiler does NOT provide correct size value for delete [] operator." << endl
|
|
<< "It should provide the same size value to delete [] as it did to new []." << endl
|
|
<< "Please ask your compiler vendor to comply with Section 12.5/5 of the C++" << endl
|
|
<< "Standard. You should NOT use Loki to allocate arrays. Please do *not*" << endl
|
|
<< "#define LOKI_SMALL_OBJECT_USE_NEW_ARRAY." << endl
|
|
<< endl;
|
|
cout << endl;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
const char * GetCompilerName( void )
|
|
{
|
|
/** @note This list of predefined compiler version macros comes from
|
|
http://predef.sourceforge.net/precomp.html Feel free to update this
|
|
function to add specific version numbers or add other compilers.
|
|
*/
|
|
#if (__INTEL_COMPILER)
|
|
return "Intel";
|
|
|
|
#elif (__ICC)
|
|
return "Intel";
|
|
|
|
#elif (__KCC)
|
|
return "Intel's KAI C++";
|
|
|
|
#elif (__MINGW32__)
|
|
return "MinGW";
|
|
|
|
#elif (__COMO__)
|
|
return "Comeau C++";
|
|
|
|
#elif (__DECC)
|
|
return "Compaq C/C++";
|
|
|
|
#elif (VAXC)
|
|
return "Compaq C/C++";
|
|
|
|
#elif (__VAXC)
|
|
return "Compaq C/C++";
|
|
|
|
#elif (_CRAYC)
|
|
return "Cray C/C++";
|
|
|
|
#elif (__CYGWIN__)
|
|
return "Cygwin";
|
|
|
|
#elif (__DCC__)
|
|
return "Diab C/C++";
|
|
|
|
#elif (__DMC__)
|
|
return "Digital Mars";
|
|
|
|
#elif (__SC__)
|
|
return "Digital Mars";
|
|
|
|
#elif (__ZTC__)
|
|
return "Digital Mars";
|
|
|
|
#elif (__EDG__)
|
|
return "EDG C++ Front End";
|
|
|
|
#elif (__GNUC__)
|
|
return "Gnu C/C++";
|
|
|
|
#elif (__HP_cc)
|
|
return "HP ANSI C/aC++";
|
|
|
|
#elif (__HP_aCC)
|
|
return "HP ANSI C/aC++";
|
|
|
|
#elif (__xlC__)
|
|
return "IBM XL C/C++";
|
|
|
|
#elif (__IBMC__)
|
|
return "IBM XL C/C++";
|
|
|
|
#elif (__IBMCPP__)
|
|
return "IBM XL C/C++";
|
|
|
|
#elif (LCC)
|
|
return "LCC";
|
|
|
|
#elif (__HIGHC__)
|
|
return "MetaWare High C/C++";
|
|
|
|
#elif (sgi)
|
|
return "MIPSpro";
|
|
|
|
#elif (__sgi)
|
|
return "MIPSpro";
|
|
|
|
#elif (__MRC__)
|
|
return "MPW C++";
|
|
|
|
#elif (MPW_C)
|
|
return "MPW C++";
|
|
|
|
#elif (MPW_CPLUS)
|
|
return "MPW C++";
|
|
|
|
#elif (__CC_NORCROFT)
|
|
return "Norcroft C";
|
|
|
|
#elif (__POCC__)
|
|
return "Pelles C";
|
|
|
|
#elif (SASC)
|
|
return "SAS/C";
|
|
|
|
#elif (__SASC)
|
|
return "SAS/C";
|
|
|
|
#elif (__SASC__)
|
|
return "SAS/C";
|
|
|
|
#elif (_SCO_DS)
|
|
return "SCO";
|
|
|
|
#elif (__SUNPRO_C)
|
|
return "Sun Workshop C/C++";
|
|
|
|
#elif (__SUNPRO_CC)
|
|
return "Sun Workshop C/C++";
|
|
|
|
#elif (__TenDRA__)
|
|
return "TenDRA C/C++";
|
|
|
|
#elif (__TINYC__)
|
|
return "Tiny C";
|
|
|
|
#elif (__USLC__)
|
|
return "USL C";
|
|
|
|
#elif (__WATCOMC__)
|
|
return "Watcom C++";
|
|
|
|
#elif (__MWERKS__)
|
|
return "MetroWerks CodeWarrior";
|
|
|
|
#elif (__TURBOC__)
|
|
return "Borland Turbo C";
|
|
|
|
#elif (__BORLANDC__)
|
|
return "Borland C++";
|
|
|
|
#elif (_MSC_VER >= 1400)
|
|
return "Microsoft 8.0 or higher";
|
|
|
|
#elif (_MSC_VER >= 1300)
|
|
return "Microsoft 7";
|
|
|
|
#elif (_MSC_VER >= 1200)
|
|
return "Microsoft 6";
|
|
|
|
#elif (_MSC_VER)
|
|
return "Microsoft, but a version lower than 6";
|
|
|
|
#else
|
|
return "an Unknown type";
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void OutputCompilerType( void )
|
|
{
|
|
cout << "Your compiler is " << GetCompilerName() << '.' << endl << endl;
|
|
|
|
const bool zeroSize = ( 0 == sizeof(EmptyThing) );
|
|
if ( zeroSize )
|
|
{
|
|
cout << "Your compiler allows datatypes to be zero bytes, which is contrary to" << endl;
|
|
cout << "the ISO C++ Standard." << endl;
|
|
}
|
|
else
|
|
{
|
|
cout << "Your compiler correctly sets the sizeof empty data types to "
|
|
<< sizeof(EmptyThing) << " byte(s) instead of zero bytes." << endl;
|
|
}
|
|
cout << "( sizeof(EmptyThing) == " << sizeof(EmptyThing) << " )" << endl << endl;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void RunTests( void )
|
|
{
|
|
|
|
char localQueen[ sizeof(Bee) ];
|
|
char localHive[ sizeof(Bee) * ArrayCount + ArrayOverhead ];
|
|
void * here = localQueen;
|
|
|
|
// test throwing new
|
|
if ( s_verbose )
|
|
cout << "Bee * queen = new Bee;" << endl;
|
|
Bee::s_expectedCall = Bee::NewScalarThrow;
|
|
Bee * queen = new Bee;
|
|
if ( s_verbose )
|
|
cout << "delete queen;" << endl;
|
|
// test normal delete
|
|
Bee::s_expectedCall = Bee::DeleteScalarWithSize;
|
|
delete queen;
|
|
|
|
// test throwing new []
|
|
if ( s_verbose )
|
|
cout << "Bee * hive = new Bee [ ArrayCount ];" << endl;
|
|
Bee::s_expectedCall = Bee::NewArrayThrow;
|
|
Bee * hive = new Bee [ ArrayCount ];
|
|
if ( s_verbose )
|
|
cout << "delete [] hive;" << endl;
|
|
// test normal delete []
|
|
Bee::s_expectedCall = Bee::DeleteArrayWithSize;
|
|
delete [] hive;
|
|
Bee::OutputArraySizeInfo();
|
|
|
|
// test nothrow new
|
|
if ( s_verbose )
|
|
cout << "Bee * queen = new nothrow Bee;" << endl;
|
|
Bee::s_expectedCall = Bee::NewScalarNoThrow;
|
|
queen = new (nothrow) Bee;
|
|
if ( s_verbose )
|
|
cout << "delete queen;" << endl;
|
|
// test normal delete
|
|
Bee::s_expectedCall = Bee::DeleteScalarWithSize;
|
|
delete queen;
|
|
|
|
// test nothrow new []
|
|
if ( s_verbose )
|
|
cout << "Bee * hive = new (nothrow) Bee [ 1000 ];" << endl;
|
|
Bee::s_expectedCall = Bee::NewArrayNoThrow;
|
|
hive = new (nothrow) Bee [ ArrayCount ];
|
|
if ( s_verbose )
|
|
cout << "delete [] hive;" << endl;
|
|
// test normal delete []
|
|
Bee::s_expectedCall = Bee::DeleteArrayWithSize;
|
|
delete [] hive;
|
|
|
|
Bee::Clear();
|
|
Bee::SetConstructorToThrow( true );
|
|
std::nothrow_t nothrow;
|
|
|
|
try
|
|
{
|
|
// test nothrow new when constructor throws.
|
|
if ( s_verbose )
|
|
cout << "Bee * queen = new nothrow Bee;" << endl;
|
|
Bee::s_expectedCall = Bee::NewScalarNoThrow;
|
|
queen = new (nothrow) Bee;
|
|
if ( s_verbose )
|
|
cout << "delete queen;" << endl;
|
|
// test normal delete
|
|
delete queen;
|
|
}
|
|
catch ( const std::exception & ex0 )
|
|
{
|
|
// nothrow delete should be called before catch block starts
|
|
if ( s_verbose )
|
|
cout << "catch ( const std::exception & ex0 )" << endl
|
|
<< "\t" << ex0.what() << endl;
|
|
}
|
|
|
|
try
|
|
{
|
|
// test nothrow new [] when constructor throws.
|
|
if ( s_verbose )
|
|
cout << "Bee * hive = new (nothrow) Bee [ 1000 ];" << endl;
|
|
Bee::s_expectedCall = Bee::NewArrayNoThrow;
|
|
hive = new (nothrow) Bee [ ArrayCount ];
|
|
if ( s_verbose )
|
|
cout << "delete queen;" << endl;
|
|
// test normal delete
|
|
delete [] hive;
|
|
}
|
|
catch ( const std::exception & ex1 )
|
|
{
|
|
// nothrow delete should be called before catch block starts
|
|
if ( s_verbose )
|
|
cout << "catch ( const std::exception & ex0 )" << endl
|
|
<< "\t" << ex1.what() << endl;
|
|
}
|
|
Bee::SetConstructorToThrow( false );
|
|
|
|
// test placement new
|
|
if ( s_verbose )
|
|
cout << "Bee * queen = new (here) Bee;" << endl;
|
|
Bee::s_expectedCall = Bee::NewScalarPlacement;
|
|
queen = new (here) Bee;
|
|
if ( s_verbose )
|
|
cout << "delete (here, queen);" << endl;
|
|
// test placement delete;
|
|
Bee::s_expectedCall = Bee::DeleteScalarPlacement;
|
|
delete (here, queen);
|
|
|
|
// test placement new []
|
|
here = localHive;
|
|
if ( s_verbose )
|
|
cout << "Bee * hive = new (here) Bee [ ArrayCount ];" << endl;
|
|
Bee::s_expectedCall = Bee::NewArrayPlacement;
|
|
hive = new (here) Bee [ ArrayCount ];
|
|
if ( s_verbose )
|
|
cout << "delete [] (here, hive);" << endl;
|
|
// test placement delete [];
|
|
Bee::s_expectedCall = Bee::DeleteArrayPlacement;
|
|
delete [] (here, hive);
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
int main( unsigned int argc, const char * const argv[] )
|
|
{
|
|
|
|
bool caught = false;
|
|
for ( unsigned int aa = 1; aa < argc; ++aa )
|
|
{
|
|
if ( ::strcmp( argv[aa], "-v" ) == 0 )
|
|
s_verbose = true;
|
|
}
|
|
|
|
OutputCompilerType();
|
|
try
|
|
{
|
|
RunTests();
|
|
}
|
|
catch ( const std::bad_alloc & ex1 )
|
|
{
|
|
caught = true;
|
|
if ( s_verbose )
|
|
cout << "catch ( const std::bad_alloc & ex1 )" << endl
|
|
<< "\t" << ex1.what() << endl;
|
|
}
|
|
catch ( const std::exception & ex2 )
|
|
{
|
|
caught = true;
|
|
if ( s_verbose )
|
|
cout << "catch ( const std::exception & ex2 )" << endl
|
|
<< "\t" << ex2.what() << endl;
|
|
}
|
|
catch ( ... )
|
|
{
|
|
caught = true;
|
|
if ( s_verbose )
|
|
cout << "catch ( ... )" << endl;
|
|
}
|
|
|
|
if ( caught )
|
|
{
|
|
Bee::IncrementErrorCount();
|
|
cout << "Tests of default new and delete operators aborted because of exception!"
|
|
<< endl;
|
|
}
|
|
|
|
cout << "Done running tests of default allocators." << endl;
|
|
cout << "Total errors detected: " << Bee::GetErrorCount() << endl;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|