Kill Your Program Before the User Does It!

Environment: VC6, VC7, Windows 9x/NT/2000/XP

I work a lot with students and I know their programming errors well. Moreover, I know my errors well, too! There is one technique that makes your program reliable. It is a trap technique that uses the assertion macros. The common C++ technique and some VC++/MFC features are described.

1. Why Must a Pointer Be Initialized to NULL?

If you have

class A{
public:
  A();
  ~A();
  //some declarations.
private:
  SomeType* m_pPointer;
  //some declarations.
};

A::~A(){
  delete m_pPointer;
}

And, if you assign a pointer outside of a constructor, you always must set it to NULL. For example:

A::A():m_pPointer(NULL){}

—Why?
—Because:

  1. If the logic of your program's execution does not create an object for this pointer, the delete operator will be executed without errors (according to the C++ language standard). If you forget to initialize the bypass pointer, it will have a random value and the deletion of this address can crash your program.
  2. By using break points and trace, you can easily find non-initialized pointers.
  3. You can use the "if" operator to test for a valid pointer, as in:
  4. if(m_pPointer){
      m_pPointer->DoSomething();
    }
    else{
      AfxMessageBox("Unexpected error #1234. Send me letter
                     please to aaa@bbb.com");
    }
    

    Probably your program will not work correctly but it will not crash in this place. It is very important. Imagine you were entering text for two hours and have not saved it. What do you prefer—crashing of the text editor or some warning?

  5. You can set debugging traps by using ASSERT macros.

2. Traps for Debugging

Insertion of break points is a good technique but they are not effective if a problem occurs inside some long circle. For example, say some condition becomes wrong after 10,000 circles of execution. To catch such a problem, VC++/MFC programmers use ASSERT macros. The ANSI assert macro is often used, too. I use the MFC ASSERT in the following examples, but it does not matter.

—How is it used?
—So:

ASSERT(condition);

Examples:

ASSERT(nWaterTemperature > 0 &&
       nWaterTemperature < 100);    // break if wrong value
ASSERT(pSomePointer);               // break if null pointer
ASSERT(0);                          // break if here

—How does it work?
—This way:

The assertion is executed as a dialog window with some assertion info (the program, the module, the assertion line) if the condition is false. The dialog has three buttons: "Break", "Repeat" ("Debug"), and "Continue" ("Ignore"). "Break" ends the program, "Continue" ignores assertion. The most useful is the "Repeat" button. Press it to open the source editor in the assertion place. You can test all variables' values here and understand what happened.

—How is it used?
—Mostly it used this way:

  1. For the control of the incoming pointers:
  2. void SomeFun(SomeType* pPointer)
    {
      ASSERT(pPointer);
      //some instructions.
    }
    
  3. You can trap strange values in the "switch" and "if" operators.
    Examples:
    switch(nRGBColors){
      case nRed:   {//some instructions.} break;
      case nGreen: {//some instructions.} break;
      case nBlue:  {//some instructions.} break;
      default: ASSERT(0);    // we should have never come here!
    }
    
    if(nWaterTemp >=0 && nWaterTemp < 50){
      //some instructions.
    }
    else if(nWaterTemp >= 50 && nWaterTemp <= 100){
      //some instructions.
    }
    else{
      ASSERT(0);    // we should have never come here!
    }
    
  4. For the values assertion:
  5. ASSERT(nSomeValue >= MinValue and nSomeValue <= MaxValue);
    ASSERT(nOtherValue != 0);
    etc.
    

Always use this technique and you will be greatly surprised how often such traps will work!

3. Lovely ASSERT Error

ASSERT( m_MyWnd.Create() );

Oh! It is an awful error! The program will work while debugging and will not work in the release mode. Remember: This is a macro that is removed in the release mode. Your window will never be created in this way. If you use MFC, do this:

VERIFY( m_MyWnd.Create() );

It works as ASSERT in the debug mode and executes m_MyWnd.Create() in the release mode.

4. Object Verification and the ASSERT_VALID MFC Macro

Using verify member of class is a widely known technique for verifying objects. If you have clear validate conditions for your object, you can create and use the verify class member. Example:

class Time
{
public:
  void Set(int h, int m);
  bool Verify(){return m_h>=0 && m_h<24 and m_m>=0 && m_m<60; }
  //some instructions.
};

void Time::Set(int h, int m)
{
  m_h = h;
  m_m = m;
  ASSERT(Verify());
}

Most MFC classes are children of CObject. It has the AssertValid virtual function that it uses for verification. If a class has the implementation of this function, it is called by the ASSERT_VALID macros. For example:

ASSERT_VALID(pView);

It checks the pointer of some CViewWnd object. If the object is invalid (null pointer or wrong window's handle), assertion is executed.

5. MFC TRACE Macros

The excursus to MFC macros is incompatible without the description of TRACE macros. There is no problem in outputting the values of variables by using streams in the console mode. From the other side, tracing variables under Windows programming is not such a trivial task. Actually, a lot of windows can be opened and closed while we are tracing something. There is no sense in making a trace output to many windows. One window is enough. For this purpose, the VC++ IDE uses an "output" window (View-Output menu point). To debug output, you can use the TRACE operator that has the same format as the printf stdio function.

Examples:

TRACE("\nThis is a trace of int variable %d.", nSomeInt);
TRACE("\nFunction OnInitialUpdate is starting.");

Links

My other articles, demo project, and collection of interesting C++ links can be found here:
http://www.brigsoft.com/edu

My software is here:
http://www.brigsoft.com.

© Alex Rest, 2003



Comments

  • ModAssert

    Posted by markvp on 05/01/2007 04:19pm

    For a flexible C++ assertion framework, check out ModAssert. It is described on http://modassert.sourceforge.net/ It offers a lot more than the assertions in Visual C++.

    Reply
  • VC6 does not support 'and' operator

    Posted by Legacy on 04/16/2003 12:00am

    Originally posted by: Mick Rattle

    Oh yeah, galathaea has read the ISO/IEC specs - great!

    But it would be even nicer if you'd show your students how to write programs that work with current compilers such as VC6, and not how to write programs that SHOULD compile as per theory, but actually DO NOT. As for VC6 - which is the most commonly used compiler, especially on the Win32/MFC-related website codeguru.com -, the 'and' operator is NOT supported !


    Compiling...
    test.cpp
    c:\Program Files\microsoft visual studio\myprojects\test\test.cpp(7) :
    error C2146: syntax error : missing ')' before identifier 'and'
    c:\Program Files\microsoft visual studio\myprojects\test\test.cpp(7) :
    error C2065: 'and' : undeclared identifier


    Why not use the '&&' operator as 99.9% of all C/C++, Java, JavaScript,... developers worldwide do ???

    There're so many different C++ frameworks, "standard" libraries and programming models out there that make our work/portability difficult - let's not start using even different operators in our language. Please.

    Reply
  • It would be better if you speak about pre and post conditions

    Posted by Legacy on 04/12/2003 12:00am

    Originally posted by: Andrew Schetinin

    Hi Alex,

    I think the article lacks a sort of introduction to the subject. It would be better if you speak about pre and post conditions, about verifying design assumptions and differ the assertions from error handling and exceptions. It is not enough to say "Hey, there is such a cool macro!".

    With all my respect,

    Andrew

    Reply
  • "Nice" Article....

    Posted by Legacy on 04/11/2003 12:00am

    Originally posted by: Michael Driller

    Nice to see how much you've learned so far.
    
    

    But from an article published on codeguru.com, I would expect not to find such nonsense like

    m_h<24 AND m_m>=0

    Looks like you'r mixing up C++ and Visual Basic. As your intend ought to be introducing newbies to the C++ language, you should think twice about the samples you provide.

    Also, it'd be great if you'd show your audience how well-formatted code should look like. Instead of

    switch(nRGBColors){
    case nRed: {//some instructions.} break;
    case nGreen: {//some instructions.} break;
    case nBlue: {//some instructions.} break;
    default: ASSERT(0);
    }

    I would expect proper line-breaking and indentation as in

    switch (nRGBColors)
    {
    case nRed:
    //some instructions
    break;
    }

    Lots of ASSERTs do not help you much if your code is unreadable.

    But: nice article, nonetheless. Although it uses the outdated ASSERT(0) style instead of the much more helpful ASSERT( !"Error message..." )


    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Intelligent N+X Redundancy, Placement Affinities, & Future Proofing in the Virtualized Data Center Virtualization brought about the ability to simplify business continuity management in IT. Workload portability and data replication capabilities mean that physical infrastructure failures no longer need impact application services, and they can rapidly be recovered even in the event of complete site failure. However, Enterprises and Service Providers face new challenges ensuring they have enough compute …

  • All businesses have a core set of applications that are critical to successful growth. These applications require a higher level of availability than other applications and services in the organization. There is a trade-off, however, to increasing application availability through traditional high-availability clustering. Businesses can see costs surge in terms of additional hardware and clustering software/support, as well as additional costs and complexities due to increased operational management …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds