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
|
||||
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
|
||||
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
|
||||
|
@ -67,6 +67,40 @@ namespace Loki
|
|||
- 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
|
||||
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:
|
||||
This policy imposes no requirements on a host class.
|
||||
*/
|
||||
|
||||
template < class Host >
|
||||
class CheckForNoThrow
|
||||
{
|
||||
|
@ -173,7 +208,8 @@ private:
|
|||
/** @class CheckForEquality
|
||||
|
||||
@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
|
||||
data members, and thereby provide the strong exception safety level by default.
|
||||
|
||||
|
@ -241,23 +277,23 @@ public:
|
|||
something is wrong.
|
||||
- Or it could assert if anything is wrong.
|
||||
- Ideally, it should be private.
|
||||
-# Implement similar functions to check for pre-conditions and post-conditions.
|
||||
Functions which verify pre-conditions and post-conditions do not need to
|
||||
check all class invariants, just conditions specific to certain public
|
||||
functions in the host class.
|
||||
-# Declare some typedef's inside the class declaration like these. Make one
|
||||
typedef for each exception policy you use. I typedef'ed the CheckForNothing
|
||||
policy as CheckInvariants because even if a function can't provide either the
|
||||
no-throw nor the no-change policies, it should still make sure the object
|
||||
remains in a valid state.
|
||||
- typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNoThrow > CheckForNoThrow;
|
||||
- typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNoChange > CheckForNoChange;
|
||||
- typedef ::Loki::ContractChecker< Host, ::Loki::CheckForEquality > CheckForEquality;
|
||||
- typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNothing > CheckInvariants;
|
||||
-# Construct a checker near the top of each member function - except in the
|
||||
validator member function. Pass the this pointer and the address of your
|
||||
validator function into the checker's constructor. You may also pass in pointers
|
||||
to function which check pre- and post-conditions.
|
||||
- It should never throw an exception.
|
||||
-# Optionally implement similar functions to check for pre-conditions and post-
|
||||
conditions. Functions which verify pre-conditions and post-conditions do
|
||||
not need to check all class invariants, just conditions specific to certain
|
||||
public functions in the host class. The post-condition function should never
|
||||
throw exceptions.
|
||||
-# Add this line in the class declaration:
|
||||
- typedef ::Loki::CheckFor< Host > CheckFor;
|
||||
-# Add one of these lines at the top of various class member functions to
|
||||
construct a checker near the top of each public function. You may also pass
|
||||
in pointers to functions which check pre- and post-conditions.
|
||||
- CheckFor::NoChangeOrThrow checker( this, &Host::IsValid );
|
||||
- CheckFor::NoThrow checker( this, &Host::IsValid );
|
||||
- CheckFor::NoChange checker( this, &Host::IsValid );
|
||||
- CheckFor::Equality checker( this, &Host::IsValid );
|
||||
- CheckFor::Invariants checker( this, &Host::IsValid );
|
||||
-# 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 changes any data members, then use CheckForEquality
|
||||
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
|
||||
|
||||
@par Exception Safety Level:
|
||||
|
@ -410,18 +466,25 @@ public:
|
|||
- The function should return true if everything is okay, but false if
|
||||
something is wrong.
|
||||
- Or it could assert if anything is wrong.
|
||||
-# If the checker is for static functions within a class, declare typedef's
|
||||
inside the class declaration like these. Make one typedef for each policy
|
||||
you use. I typedef'ed the CheckForNothing policy as CheckInvariants because
|
||||
even if a function can't provide the no-throw guarantee, it should still
|
||||
make sure that static data remains in a valid state.
|
||||
- typedef ::Loki::StaticChecker< ::Loki::CheckForNoThrow > CheckStaticForNoThrow;
|
||||
- typedef ::Loki::StaticChecker< ::Loki::CheckForNothing > CheckStaticInvariants;
|
||||
-# Construct a checker near the top of each member function - except in the
|
||||
validator member function. Pass the address of your validator function into
|
||||
the checker's constructor.
|
||||
- But it should never throw an exception.
|
||||
-# If the checker validates static functions within a class, add this line to
|
||||
the class declaration.
|
||||
- typedef ::Loki::CheckStaticFor CheckStaticFor;
|
||||
-# Construct a checker near the top of each member function using one of
|
||||
these lines:
|
||||
- CheckStaticFor::NoThrow checker( &Host::StaticIsValid );
|
||||
- CheckStaticFor::Invariants checker( &Host::StaticIsValid );
|
||||
-# These guidelines can help you decide which exception policy to use within
|
||||
each function.
|
||||
- If the function never throws, then use the CheckForNoThrow 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
|
||||
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
|
||||
|
||||
#endif
|
||||
|
|
|
@ -92,16 +92,11 @@ private:
|
|||
/// This can be used to validate pre-conditions and post-conditions.
|
||||
bool IsValidFull( void ) const;
|
||||
|
||||
// These lines show how to declare checkers for non-static functions in a host class.
|
||||
typedef ::Loki::ContractChecker< Thingy, ::Loki::CheckForNoThrow > CheckForNoThrow;
|
||||
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;
|
||||
// This shows how to declare checkers for non-static functions in a host class.
|
||||
typedef ::Loki::CheckFor< Thingy > CheckFor;
|
||||
|
||||
// These lines show how to declare checkers for static functions of a host class.
|
||||
typedef ::Loki::StaticChecker< ::Loki::CheckStaticForNoThrow > CheckStaticForNoThrow;
|
||||
typedef ::Loki::StaticChecker< ::Loki::CheckStaticForNothing > CheckStaticInvariants;
|
||||
// This shows how to declare checkers for static functions of a host class.
|
||||
typedef ::Loki::CheckStaticFor CheckStaticFor;
|
||||
|
||||
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.
|
||||
void Thingy::ChangeThat( void )
|
||||
{
|
||||
CheckStaticForNoThrow checker( &Thingy::StaticIsValid );
|
||||
CheckStaticFor::NoThrow checker( &Thingy::StaticIsValid );
|
||||
(void)checker;
|
||||
s_value--;
|
||||
}
|
||||
|
@ -130,7 +125,7 @@ void Thingy::ChangeThat( void )
|
|||
// This example shows how static functions can use an invariant checker.
|
||||
unsigned int Thingy::GetThat( void )
|
||||
{
|
||||
CheckStaticInvariants checker( &Thingy::StaticIsValid );
|
||||
CheckStaticFor::Invariants checker( &Thingy::StaticIsValid );
|
||||
(void)checker;
|
||||
return s_value;
|
||||
}
|
||||
|
@ -142,7 +137,7 @@ Thingy::Thingy( unsigned int value ) :
|
|||
m_value( value ),
|
||||
m_counts()
|
||||
{
|
||||
CheckInvariants checker( this, &Thingy::IsValid );
|
||||
CheckFor::Invariants checker( this, &Thingy::IsValid );
|
||||
(void)checker;
|
||||
}
|
||||
|
||||
|
@ -152,7 +147,7 @@ Thingy::Thingy( const Thingy & that ) :
|
|||
m_value( that.m_value ),
|
||||
m_counts( that.m_counts )
|
||||
{
|
||||
CheckInvariants checker( this, &Thingy::IsValid );
|
||||
CheckFor::Invariants checker( this, &Thingy::IsValid );
|
||||
(void)checker;
|
||||
}
|
||||
|
||||
|
@ -160,7 +155,7 @@ Thingy::Thingy( const Thingy & that ) :
|
|||
|
||||
Thingy & Thingy::operator = ( const Thingy & that )
|
||||
{
|
||||
CheckInvariants checker( this, &Thingy::IsValid );
|
||||
CheckFor::Invariants checker( this, &Thingy::IsValid );
|
||||
(void)checker;
|
||||
if ( &that != this )
|
||||
{
|
||||
|
@ -184,9 +179,9 @@ Thingy::~Thingy( void )
|
|||
// A swap function gets 2 checkers - one for this, and another for that.
|
||||
void Thingy::Swap( Thingy & that )
|
||||
{
|
||||
CheckInvariants checker1( this, &Thingy::IsValid );
|
||||
CheckFor::Invariants checker1( this, &Thingy::IsValid );
|
||||
(void)checker1;
|
||||
CheckInvariants checker2( &that, &Thingy::IsValid );
|
||||
CheckFor::Invariants checker2( &that, &Thingy::IsValid );
|
||||
(void)checker2;
|
||||
|
||||
const IntBlock counts( m_counts );
|
||||
|
@ -216,7 +211,7 @@ void Thingy::DoSomethingEvil( void )
|
|||
// This example shows how to use the no-throw checker.
|
||||
unsigned int Thingy::GetValue( void ) const
|
||||
{
|
||||
CheckForNoThrow checker( this, &Thingy::IsValid );
|
||||
CheckFor::NoThrow checker( this, &Thingy::IsValid );
|
||||
(void)checker;
|
||||
return m_value;
|
||||
}
|
||||
|
@ -226,7 +221,7 @@ unsigned int Thingy::GetValue( void ) const
|
|||
// This example shows how to use the equality checker.
|
||||
unsigned int Thingy::DoSomething( bool doThrow ) const
|
||||
{
|
||||
CheckForEquality checker( this, &Thingy::IsValid );
|
||||
CheckFor::Equality checker( this, &Thingy::IsValid );
|
||||
(void)checker;
|
||||
if ( doThrow )
|
||||
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.
|
||||
void Thingy::DoSomethingElse( void ) const
|
||||
{
|
||||
CheckForNoChange checker( this, &Thingy::IsValid );
|
||||
CheckFor::NoChange checker( this, &Thingy::IsValid );
|
||||
(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
|
||||
// the pre-condition validator. Ths post-condition validator just makes sure
|
||||
// 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 );
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
// 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.
|
||||
CheckForNoChangeOrThrow checker( this, &Thingy::IsValid, &Thingy::IsValidFull, &Thingy::IsValidFull );
|
||||
CheckFor::NoChangeOrThrow checker( this, &Thingy::IsValid, &Thingy::IsValidFull, &Thingy::IsValidFull );
|
||||
if ( m_counts.size() <= index )
|
||||
return 0;
|
||||
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
|
||||
// the pre-condition validator. Ths post-condition validator just makes sure
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
@ -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 )
|
||||
{
|
||||
// This example shows how to use a checker in a stand-alone function.
|
||||
CheckStaticForNoThrow checker( &AllIsValid );
|
||||
::Loki::CheckStaticFor::NoThrow checker( &AllIsValid );
|
||||
(void)checker;
|
||||
Thingy::ChangeThat();
|
||||
}
|
||||
|
@ -355,6 +344,8 @@ void ThrowTest( void )
|
|||
int main( unsigned int argc, const char * const argv[] )
|
||||
{
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
try
|
||||
{
|
||||
cout << "Just before call to ThrowTest." << endl;
|
||||
|
|
Loading…
Reference in a new issue