Books
in black and white
Main menu
Share a book About us Home
Books
Biology Business Chemistry Computers Culture Economics Fiction Games Guide History Management Mathematical Medicine Mental Fitnes Physics Psychology Scince Sport Technics
Ads

Symbian os Expleined effective C++ programming for smartphones - Batchelor D.

Batchelor D. Symbian os Expleined effective C++ programming for smartphones - Wiley publishing , 2005. - 394 p.
ISBN 0-470-02130-6
Download (direct link): symbianosexpltivec++2005.pdf
Previous << 1 .. 108 109 110 111 112 113 < 114 > 115 116 117 118 119 120 .. 151 >> Next

It's good practice to use the uheap_x macros to verify that
your code does not leak memory. You can put uheap_mark and
uheap_markend pairs in your test code and, since the macros
are not compiled into release builds, you can use them to surround areas where leaks may occur in your production code too.
270
DEBUG MACROS AND TEST CLASSES
17.2 Object Invariance Macros
The DECLARE_TEST and TEST_INVARIANT macros allow you to
check the state of an object, for example at the beginning and end of
a complex function. The DECLARE_TEST macro provides a standard
way to add a function to a class that allows object invariance to be tested.
This function is named DbgTestInvariant() and you should define
it as necessary. When performing the invariance testing, rather than call
the function directly, you should use the TEST_INVARIANT macro,
as I'll show shortly.
DECLARE_TEST is defined as follows in e32def.h:
#if defined( DLL )
#define DECLARE_TEST public: IMPORT_C void DbgTestInvariant()
const; void DbgTest(TAny *aPtr) const
#else
#define __DECLARE_TEST public: void __DbgTestInvariant() const; void __DbgTest(TAny *aPtr) const
#endif
You should add it to any class for which you wish to perform an object invariance test. It's best to add it to the bottom of the class declaration because it uses the public access specifier. There are separate definitions for DLLs and EXEs because the function must be exported from a DLL so it may be called from a separate module. The second function defined
by DECLARE_TEST, DbgTest(), is designed to allow test code
to access non-public members of the class, if such testing is required. Because any test code will implement this function itself, it is not exported.
The DECLARE_TEST macro is defined to be the same for both
release and debug builds, because otherwise the export list for debug builds would have an extra function ( DbgTestInvariant()) compared to the release version. This could cause binary compatibility problems, by changing the ordinal numbers of other exported functions in the module. (Chapter 18 discusses binary compatibility in more detail.)
The TEST_INVARIANT macro is defined below; as you can see,
it doesn't call DbgTestInvariant() in release builds. However, if
you don't want the invariance test code to be built into release builds, you should surround it with preprocessor directives as appropriate to build the invariance testing into debug builds only.
#if defined(_DEBUG)
#define TEST_INVARIANT DbgTestInvariant()
#else
#define TEST_INVARIANT
#endif
OBJECT INVARIANCE MACROS
The invariance test function, DbgTestInvariant(), typically
checks that the object's state is correct at the beginning and end of a function. If the state is invalid, a panic should be raised by calling User::Invariant() (which panics with category USER, reason 0). You may recall, from Chapter 16, that this is the panic raised by the ASSERT macro. Thus a simple way to implement the invariance testing
in DbgTestInvariant() is to perform the invariance checks inside
ASSERT statements.
Here's an example of a class that represents a living person and uses the DECLARE_TEST invariance test to verify that:
• the person has a gender
• if the name is set, it is a valid string of length no greater than 250 characters
• the given age in years matches the age calculated for the given date of birth and is no greater than 140 years.
class CLivingPerson: public CBase {
public:
enum TGender {EMale, EFemale}; public:
static CLivingPerson* NewL(const TDesC& aName,
CLivingPerson::TGender aGender);
~CLivingPerson();
public:
... // Other methods omitted for clarity void SetDOBAndAge(const TTime& aDOB, const TInt aAge); private:
CLivingPerson(TGender aGender); void ConstructL(const TDesC& aName); private:
HBufC* iName;
TGender iGender;
TInt iAgeInYears;
TTime iDOB; // Date of Birth
__DECLARE_TEST; // Object invariance testing };
CLivingPerson::CLivingPerson(TGender aGender)
: iGender(aGender) {}
CLivingPerson::^CLivingPerson()
{delete iName;}
CLivingPerson* CLivingPerson::NewL(const TDesC& aName, CLivingPerson::TGender aGender)
{
CLivingPerson* me = new (ELeave) CLivingPerson(aGender);
CleanupStack::PushL(me);
me->ConstructL(aName);
CleanupStack::Pop(me);
272
DEBUG MACROS AND TEST CLASSES
return (me);
}
void CLivingPerson::ConstructL(const TDesCk aName)
{
TEST_INVARIANT;
iName = aName.AllocL();
__TEST_INVARIANT;
}
void CLivingPerson::SetDOBAndAge(const TTimek aDOB, const TInt aAge)
{// Store the DOB and age and check object invariance
__TEST_INVARIANT;
iDOB=aDOB;
iAgeInYears=aAge;
__TEST_INVARIANT;
}
void CLivingPerson::____DbgTestInvariant() const
{
#ifdef _DEBUG // Built into debug code only if (iName)
{// Name should be more than 0 but not longer than 250 chars TInt len = iName->Length();
ASSERT(len>0); // A zero length name is invalid
ASSERT(len<250); // The name should be less than 250 characters
}
// Person should male or female ASSERT((EMale==iGender)||(EFemale==iGender));
Previous << 1 .. 108 109 110 111 112 113 < 114 > 115 116 117 118 119 120 .. 151 >> Next