Added structs to declare typedefs for various exception policies.
git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@1012 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
parent
433534f136
commit
e35ba7770e
2 changed files with 130 additions and 58 deletions
|
@ -39,7 +39,7 @@ namespace Loki
|
||||||
|
|
||||||
@par Class & Data Invariants
|
@par Class & Data Invariants
|
||||||
The ContractChecker and StaticChecker define invariants as "expressions that
|
The ContractChecker and StaticChecker define invariants as "expressions that
|
||||||
are true for particular data". They uses a function which returns true if all
|
are true for particular data". They call a function which returns true if all
|
||||||
data are valid, and returns false if any datum is invalid. This is called the
|
data are valid, and returns false if any datum is invalid. This is called the
|
||||||
validator function, and the host class or function provides a pointer to it.
|
validator function, and the host class or function provides a pointer to it.
|
||||||
The validator could also assert for any invariant which fails rather than
|
The validator could also assert for any invariant which fails rather than
|
||||||
|
@ -67,6 +67,40 @@ namespace Loki
|
||||||
- Basic guarantee: A function will not leak resources and data will remain
|
- Basic guarantee: A function will not leak resources and data will remain
|
||||||
in a valid state if an exception occurs. (Which I call either the no-leak
|
in a valid state if an exception occurs. (Which I call either the no-leak
|
||||||
or no-break guarantee depending on context.)
|
or no-break guarantee depending on context.)
|
||||||
|
|
||||||
|
@par Writing Your Own Policies
|
||||||
|
Loki provides several exception policies for ContractChecker. These policies
|
||||||
|
assert if an object changed or a function threw an exception. If you prefer
|
||||||
|
policies that log failures to a file, pop-up a message box, notify your unit-
|
||||||
|
test framework, or whatever else, you can easily write your own policies.
|
||||||
|
Your policy class should have two functions, a constructor and a Check
|
||||||
|
function, both of which accept a pointer to const instance of the host class.
|
||||||
|
Your policy class will become a base class of ContractChecker. Check should
|
||||||
|
return true if all is okay, and false if any failure was detected. Check
|
||||||
|
should never throw any exceptions since it is called from ContractChecker's
|
||||||
|
destructor. You may add other functions to the policy class. This code
|
||||||
|
snippet shows the signatures for the two required functions.
|
||||||
|
@code
|
||||||
|
class YourPolicy
|
||||||
|
{ public:
|
||||||
|
explicit YourPolicy( const Host * );
|
||||||
|
bool Check( const Host * ) const;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
Loki provides two exception policies for StaticChecker - one that asserts if
|
||||||
|
an exception occurred, and one that does not care about exceptions. You can
|
||||||
|
make your own policy to log failures, send an email, file a bug report, or do
|
||||||
|
whatever. Just write a policy with a default constructor and a function call
|
||||||
|
Check which look like those shown below. Make sure your Check function never
|
||||||
|
throws any exceptions. Any additional functions or features of the policy
|
||||||
|
are up to you.
|
||||||
|
@code
|
||||||
|
class YourPolicy
|
||||||
|
{ public:
|
||||||
|
YourPolicy();
|
||||||
|
bool Check() const;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -81,6 +115,7 @@ namespace Loki
|
||||||
@par Requirements For Host Class:
|
@par Requirements For Host Class:
|
||||||
This policy imposes no requirements on a host class.
|
This policy imposes no requirements on a host class.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template < class Host >
|
template < class Host >
|
||||||
class CheckForNoThrow
|
class CheckForNoThrow
|
||||||
{
|
{
|
||||||
|
@ -173,7 +208,8 @@ private:
|
||||||
/** @class CheckForEquality
|
/** @class CheckForEquality
|
||||||
|
|
||||||
@par Exception Safety Level:
|
@par Exception Safety Level:
|
||||||
This exception-checking policy class for ContractChecker asserts if a copy of the host differs from the host object regardless of whether an exception occurs.
|
This exception-checking policy class for ContractChecker asserts if a copy of
|
||||||
|
the host differs from the host object regardless of whether an exception occurs.
|
||||||
Host classes can use this policy to show which member functions never change
|
Host classes can use this policy to show which member functions never change
|
||||||
data members, and thereby provide the strong exception safety level by default.
|
data members, and thereby provide the strong exception safety level by default.
|
||||||
|
|
||||||
|
@ -241,23 +277,23 @@ public:
|
||||||
something is wrong.
|
something is wrong.
|
||||||
- Or it could assert if anything is wrong.
|
- Or it could assert if anything is wrong.
|
||||||
- Ideally, it should be private.
|
- Ideally, it should be private.
|
||||||
-# Implement similar functions to check for pre-conditions and post-conditions.
|
- It should never throw an exception.
|
||||||
Functions which verify pre-conditions and post-conditions do not need to
|
-# Optionally implement similar functions to check for pre-conditions and post-
|
||||||
check all class invariants, just conditions specific to certain public
|
conditions. Functions which verify pre-conditions and post-conditions do
|
||||||
functions in the host class.
|
not need to check all class invariants, just conditions specific to certain
|
||||||
-# Declare some typedef's inside the class declaration like these. Make one
|
public functions in the host class. The post-condition function should never
|
||||||
typedef for each exception policy you use. I typedef'ed the CheckForNothing
|
throw exceptions.
|
||||||
policy as CheckInvariants because even if a function can't provide either the
|
-# Add this line in the class declaration:
|
||||||
no-throw nor the no-change policies, it should still make sure the object
|
- typedef ::Loki::CheckFor< Host > CheckFor;
|
||||||
remains in a valid state.
|
-# Add one of these lines at the top of various class member functions to
|
||||||
- typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNoThrow > CheckForNoThrow;
|
construct a checker near the top of each public function. You may also pass
|
||||||
- typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNoChange > CheckForNoChange;
|
in pointers to functions which check pre- and post-conditions.
|
||||||
- typedef ::Loki::ContractChecker< Host, ::Loki::CheckForEquality > CheckForEquality;
|
- CheckFor::NoChangeOrThrow checker( this, &Host::IsValid );
|
||||||
- typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNothing > CheckInvariants;
|
- CheckFor::NoThrow checker( this, &Host::IsValid );
|
||||||
-# Construct a checker near the top of each member function - except in the
|
- CheckFor::NoChange checker( this, &Host::IsValid );
|
||||||
validator member function. Pass the this pointer and the address of your
|
- CheckFor::Equality checker( this, &Host::IsValid );
|
||||||
validator function into the checker's constructor. You may also pass in pointers
|
- CheckFor::Invariants checker( this, &Host::IsValid );
|
||||||
to function which check pre- and post-conditions.
|
-# Use these guidelines to decide which policy to use inside which function:
|
||||||
- If the function never throws, then use the CheckForNoThrow policy.
|
- If the function never throws, then use the CheckForNoThrow policy.
|
||||||
- If the function never changes any data members, then use CheckForEquality
|
- If the function never changes any data members, then use CheckForEquality
|
||||||
policy.
|
policy.
|
||||||
|
@ -362,6 +398,26 @@ private:
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** @struct CheckFor
|
||||||
|
This struct declares types of checkers used to validate a host object. All of
|
||||||
|
Loki's exception-checking policies are named here as typedef's so host classes
|
||||||
|
have a one-stop convenience place for declaring them. If you write your own
|
||||||
|
exception policies for ContractChecker, you might want to also write a struct
|
||||||
|
similiar to CheckFor to conveniently declare all your policies.
|
||||||
|
*/
|
||||||
|
template < class Host >
|
||||||
|
struct CheckFor
|
||||||
|
{
|
||||||
|
// These lines declare checkers for non-static functions in a host class.
|
||||||
|
typedef ContractChecker< Host, CheckForNoChangeOrThrow > NoChangeOrThrow;
|
||||||
|
typedef ContractChecker< Host, CheckForNoThrow > NoThrow;
|
||||||
|
typedef ContractChecker< Host, CheckForNoChange > NoChange;
|
||||||
|
typedef ContractChecker< Host, CheckForEquality > Equality;
|
||||||
|
typedef ContractChecker< Host, CheckForNothing > Invariants;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/** @class CheckStaticForNoThrow
|
/** @class CheckStaticForNoThrow
|
||||||
|
|
||||||
@par Exception Safety Level:
|
@par Exception Safety Level:
|
||||||
|
@ -410,18 +466,25 @@ public:
|
||||||
- The function should return true if everything is okay, but false if
|
- The function should return true if everything is okay, but false if
|
||||||
something is wrong.
|
something is wrong.
|
||||||
- Or it could assert if anything is wrong.
|
- Or it could assert if anything is wrong.
|
||||||
-# If the checker is for static functions within a class, declare typedef's
|
- But it should never throw an exception.
|
||||||
inside the class declaration like these. Make one typedef for each policy
|
-# If the checker validates static functions within a class, add this line to
|
||||||
you use. I typedef'ed the CheckForNothing policy as CheckInvariants because
|
the class declaration.
|
||||||
even if a function can't provide the no-throw guarantee, it should still
|
- typedef ::Loki::CheckStaticFor CheckStaticFor;
|
||||||
make sure that static data remains in a valid state.
|
-# Construct a checker near the top of each member function using one of
|
||||||
- typedef ::Loki::StaticChecker< ::Loki::CheckForNoThrow > CheckStaticForNoThrow;
|
these lines:
|
||||||
- typedef ::Loki::StaticChecker< ::Loki::CheckForNothing > CheckStaticInvariants;
|
- CheckStaticFor::NoThrow checker( &Host::StaticIsValid );
|
||||||
-# Construct a checker near the top of each member function - except in the
|
- CheckStaticFor::Invariants checker( &Host::StaticIsValid );
|
||||||
validator member function. Pass the address of your validator function into
|
-# These guidelines can help you decide which exception policy to use within
|
||||||
the checker's constructor.
|
each function.
|
||||||
- If the function never throws, then use the CheckForNoThrow policy.
|
- If the function never throws, then use the CheckForNoThrow policy.
|
||||||
- Otherwise use the CheckInvariants policy.
|
- Otherwise use the CheckInvariants policy.
|
||||||
|
-# If the checker validates standalone functions, then just add one of these
|
||||||
|
lines at the top of the function. You may also want to write validation
|
||||||
|
functions which check pre-conditions and post-conditions of standalone
|
||||||
|
functions which you can pass into the checker as optional 2nd and 3rd
|
||||||
|
parameters.
|
||||||
|
- ::Loki::CheckStaticFor::NoThrow checker( &AllIsValid );
|
||||||
|
- ::Loki::CheckStaticFor::Invariants checker( &AllIsValid );
|
||||||
-# Recompile a debug version of your program, run it, and see if an assertion
|
-# Recompile a debug version of your program, run it, and see if an assertion
|
||||||
fails.
|
fails.
|
||||||
*/
|
*/
|
||||||
|
@ -511,6 +574,24 @@ private:
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** @struct CheckStaticFor
|
||||||
|
This struct declares types of checkers used to validate standalone functions
|
||||||
|
and class static functions. All of Loki's exception-checking policies for
|
||||||
|
StaticChecker are named here as typedef's. If you write your own
|
||||||
|
exception policies for StaticChecker, you might want to also write a struct
|
||||||
|
similiar to CheckStaticFor to conveniently declare all your policies.
|
||||||
|
*/
|
||||||
|
struct CheckStaticFor
|
||||||
|
{
|
||||||
|
// These lines declare checkers for static functions of a host class
|
||||||
|
// or for standalone functions outside any class or struct.
|
||||||
|
typedef StaticChecker< CheckStaticForNoThrow > NoThrow;
|
||||||
|
typedef StaticChecker< CheckStaticForNothing > Invariants;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
}; // end namespace Loki
|
}; // end namespace Loki
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -92,16 +92,11 @@ private:
|
||||||
/// This can be used to validate pre-conditions and post-conditions.
|
/// This can be used to validate pre-conditions and post-conditions.
|
||||||
bool IsValidFull( void ) const;
|
bool IsValidFull( void ) const;
|
||||||
|
|
||||||
// These lines show how to declare checkers for non-static functions in a host class.
|
// This shows how to declare checkers for non-static functions in a host class.
|
||||||
typedef ::Loki::ContractChecker< Thingy, ::Loki::CheckForNoThrow > CheckForNoThrow;
|
typedef ::Loki::CheckFor< Thingy > CheckFor;
|
||||||
typedef ::Loki::ContractChecker< Thingy, ::Loki::CheckForNoChangeOrThrow > CheckForNoChangeOrThrow;
|
|
||||||
typedef ::Loki::ContractChecker< Thingy, ::Loki::CheckForNoChange > CheckForNoChange;
|
|
||||||
typedef ::Loki::ContractChecker< Thingy, ::Loki::CheckForEquality > CheckForEquality;
|
|
||||||
typedef ::Loki::ContractChecker< Thingy, ::Loki::CheckForNothing > CheckInvariants;
|
|
||||||
|
|
||||||
// These lines show how to declare checkers for static functions of a host class.
|
// This shows how to declare checkers for static functions of a host class.
|
||||||
typedef ::Loki::StaticChecker< ::Loki::CheckStaticForNoThrow > CheckStaticForNoThrow;
|
typedef ::Loki::CheckStaticFor CheckStaticFor;
|
||||||
typedef ::Loki::StaticChecker< ::Loki::CheckStaticForNothing > CheckStaticInvariants;
|
|
||||||
|
|
||||||
typedef ::std::vector< unsigned int > IntBlock;
|
typedef ::std::vector< unsigned int > IntBlock;
|
||||||
|
|
||||||
|
@ -120,7 +115,7 @@ unsigned int Thingy::s_value = 10;
|
||||||
// This example shows how static functions can use a no-throw checkers.
|
// This example shows how static functions can use a no-throw checkers.
|
||||||
void Thingy::ChangeThat( void )
|
void Thingy::ChangeThat( void )
|
||||||
{
|
{
|
||||||
CheckStaticForNoThrow checker( &Thingy::StaticIsValid );
|
CheckStaticFor::NoThrow checker( &Thingy::StaticIsValid );
|
||||||
(void)checker;
|
(void)checker;
|
||||||
s_value--;
|
s_value--;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +125,7 @@ void Thingy::ChangeThat( void )
|
||||||
// This example shows how static functions can use an invariant checker.
|
// This example shows how static functions can use an invariant checker.
|
||||||
unsigned int Thingy::GetThat( void )
|
unsigned int Thingy::GetThat( void )
|
||||||
{
|
{
|
||||||
CheckStaticInvariants checker( &Thingy::StaticIsValid );
|
CheckStaticFor::Invariants checker( &Thingy::StaticIsValid );
|
||||||
(void)checker;
|
(void)checker;
|
||||||
return s_value;
|
return s_value;
|
||||||
}
|
}
|
||||||
|
@ -142,7 +137,7 @@ Thingy::Thingy( unsigned int value ) :
|
||||||
m_value( value ),
|
m_value( value ),
|
||||||
m_counts()
|
m_counts()
|
||||||
{
|
{
|
||||||
CheckInvariants checker( this, &Thingy::IsValid );
|
CheckFor::Invariants checker( this, &Thingy::IsValid );
|
||||||
(void)checker;
|
(void)checker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +147,7 @@ Thingy::Thingy( const Thingy & that ) :
|
||||||
m_value( that.m_value ),
|
m_value( that.m_value ),
|
||||||
m_counts( that.m_counts )
|
m_counts( that.m_counts )
|
||||||
{
|
{
|
||||||
CheckInvariants checker( this, &Thingy::IsValid );
|
CheckFor::Invariants checker( this, &Thingy::IsValid );
|
||||||
(void)checker;
|
(void)checker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +155,7 @@ Thingy::Thingy( const Thingy & that ) :
|
||||||
|
|
||||||
Thingy & Thingy::operator = ( const Thingy & that )
|
Thingy & Thingy::operator = ( const Thingy & that )
|
||||||
{
|
{
|
||||||
CheckInvariants checker( this, &Thingy::IsValid );
|
CheckFor::Invariants checker( this, &Thingy::IsValid );
|
||||||
(void)checker;
|
(void)checker;
|
||||||
if ( &that != this )
|
if ( &that != this )
|
||||||
{
|
{
|
||||||
|
@ -184,9 +179,9 @@ Thingy::~Thingy( void )
|
||||||
// A swap function gets 2 checkers - one for this, and another for that.
|
// A swap function gets 2 checkers - one for this, and another for that.
|
||||||
void Thingy::Swap( Thingy & that )
|
void Thingy::Swap( Thingy & that )
|
||||||
{
|
{
|
||||||
CheckInvariants checker1( this, &Thingy::IsValid );
|
CheckFor::Invariants checker1( this, &Thingy::IsValid );
|
||||||
(void)checker1;
|
(void)checker1;
|
||||||
CheckInvariants checker2( &that, &Thingy::IsValid );
|
CheckFor::Invariants checker2( &that, &Thingy::IsValid );
|
||||||
(void)checker2;
|
(void)checker2;
|
||||||
|
|
||||||
const IntBlock counts( m_counts );
|
const IntBlock counts( m_counts );
|
||||||
|
@ -216,7 +211,7 @@ void Thingy::DoSomethingEvil( void )
|
||||||
// This example shows how to use the no-throw checker.
|
// This example shows how to use the no-throw checker.
|
||||||
unsigned int Thingy::GetValue( void ) const
|
unsigned int Thingy::GetValue( void ) const
|
||||||
{
|
{
|
||||||
CheckForNoThrow checker( this, &Thingy::IsValid );
|
CheckFor::NoThrow checker( this, &Thingy::IsValid );
|
||||||
(void)checker;
|
(void)checker;
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
@ -226,7 +221,7 @@ unsigned int Thingy::GetValue( void ) const
|
||||||
// This example shows how to use the equality checker.
|
// This example shows how to use the equality checker.
|
||||||
unsigned int Thingy::DoSomething( bool doThrow ) const
|
unsigned int Thingy::DoSomething( bool doThrow ) const
|
||||||
{
|
{
|
||||||
CheckForEquality checker( this, &Thingy::IsValid );
|
CheckFor::Equality checker( this, &Thingy::IsValid );
|
||||||
(void)checker;
|
(void)checker;
|
||||||
if ( doThrow )
|
if ( doThrow )
|
||||||
throw ::std::logic_error( "Test Exception." );
|
throw ::std::logic_error( "Test Exception." );
|
||||||
|
@ -238,7 +233,7 @@ unsigned int Thingy::DoSomething( bool doThrow ) const
|
||||||
// This example shows how to use the no-change checker.
|
// This example shows how to use the no-change checker.
|
||||||
void Thingy::DoSomethingElse( void ) const
|
void Thingy::DoSomethingElse( void ) const
|
||||||
{
|
{
|
||||||
CheckForNoChange checker( this, &Thingy::IsValid );
|
CheckFor::NoChange checker( this, &Thingy::IsValid );
|
||||||
(void)checker;
|
(void)checker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +245,7 @@ void Thingy::AddCount( unsigned int count )
|
||||||
// but does not need to check pre-conditions, so it passes in a nullptr for
|
// but does not need to check pre-conditions, so it passes in a nullptr for
|
||||||
// the pre-condition validator. Ths post-condition validator just makes sure
|
// the pre-condition validator. Ths post-condition validator just makes sure
|
||||||
// the container has at least 1 element.
|
// the container has at least 1 element.
|
||||||
CheckInvariants checker( this, &Thingy::IsValid, nullptr, &Thingy::IsValidFull );
|
CheckFor::Invariants checker( this, &Thingy::IsValid, nullptr, &Thingy::IsValidFull );
|
||||||
m_counts.push_back( count );
|
m_counts.push_back( count );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +256,7 @@ unsigned int Thingy::GetCount( unsigned int index ) const
|
||||||
// This function's checker cares about class invariants and both the pre- and
|
// This function's checker cares about class invariants and both the pre- and
|
||||||
// post-conditions, so it passes in pointers for all 3 validators. The pre-
|
// post-conditions, so it passes in pointers for all 3 validators. The pre-
|
||||||
// and post-conditions are both about making sure the container is not empty.
|
// and post-conditions are both about making sure the container is not empty.
|
||||||
CheckForNoChangeOrThrow checker( this, &Thingy::IsValid, &Thingy::IsValidFull, &Thingy::IsValidFull );
|
CheckFor::NoChangeOrThrow checker( this, &Thingy::IsValid, &Thingy::IsValidFull, &Thingy::IsValidFull );
|
||||||
if ( m_counts.size() <= index )
|
if ( m_counts.size() <= index )
|
||||||
return 0;
|
return 0;
|
||||||
const unsigned int count = m_counts[ index ];
|
const unsigned int count = m_counts[ index ];
|
||||||
|
@ -276,7 +271,7 @@ void Thingy::ClearCounts( void )
|
||||||
// but does not need to check pre-conditions, so it passes in a nullptr for
|
// but does not need to check pre-conditions, so it passes in a nullptr for
|
||||||
// the pre-condition validator. Ths post-condition validator just makes sure
|
// the pre-condition validator. Ths post-condition validator just makes sure
|
||||||
// the container has no elements.
|
// the container has no elements.
|
||||||
CheckForNoThrow checker( this, &Thingy::IsValid, nullptr, &Thingy::IsValidEmpty );
|
CheckFor::NoThrow checker( this, &Thingy::IsValid, nullptr, &Thingy::IsValidEmpty );
|
||||||
m_counts.clear();
|
m_counts.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,16 +323,10 @@ bool AllIsValid( void )
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// These lines show how to declare checkers for standalone functions.
|
|
||||||
typedef ::Loki::StaticChecker< ::Loki::CheckStaticForNoThrow > CheckStaticForNoThrow;
|
|
||||||
typedef ::Loki::StaticChecker< ::Loki::CheckStaticForNothing > CheckStaticInvariants;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void DoSomething( void )
|
void DoSomething( void )
|
||||||
{
|
{
|
||||||
// This example shows how to use a checker in a stand-alone function.
|
// This example shows how to use a checker in a stand-alone function.
|
||||||
CheckStaticForNoThrow checker( &AllIsValid );
|
::Loki::CheckStaticFor::NoThrow checker( &AllIsValid );
|
||||||
(void)checker;
|
(void)checker;
|
||||||
Thingy::ChangeThat();
|
Thingy::ChangeThat();
|
||||||
}
|
}
|
||||||
|
@ -355,6 +344,8 @@ void ThrowTest( void )
|
||||||
int main( unsigned int argc, const char * const argv[] )
|
int main( unsigned int argc, const char * const argv[] )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
cout << "Just before call to ThrowTest." << endl;
|
cout << "Just before call to ThrowTest." << endl;
|
||||||
|
|
Loading…
Reference in a new issue