Kill Your Program Before the User Does It!

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

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 [email protected]");
    }
    

    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

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read