Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Tips and Traps for young programmers

0.00/5 (No votes)
24 Apr 2003 1  
Kill your program before the user will do it! Traps techniques and VC++/C++ notes for beginners

Introduction

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. Common C++ techniques and some VC++/MFC features are also described.

Why must a pointer be initialized to NULL?

If you have

class A{
public:
    A();
    ~A();
    //some declarations ...

    private:
    pSomeType* 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?

  1. If the logic of the execution of your program does not create an object for this pointer the delete operator will be executed without errors (according the c++ language standard). If you forget the initialization of the bypass pointer it will have a random value and the deletion of this address can crash your program.
  2. Using break points and trace you can easily find non-initialized pointers.
  3. You can use "if" operator to do for a valid pointer something as
    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?

  4. You can set debugging traps using ASSERT macros.

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, some condition becomes wrong after 10000 circles of execution. For catching such problem VC++/MFC programmers use ASSERT macros. The ANSI assert macro is often used too. I use the MFC ASSERT in examples below, but it does not matter.

How is it used -  (Some 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?

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"), "Continue"("Ignore"). "Break" ends the program, "Continue" ignores assertion. The most useful is the "Repeat" button. Press it to open source editor in the assertion place. You can test all variables' values here and understand what happened.

How is it used?

For the control of the incoming pointers:

void SomeFun(SomeType* pPointer)
{
 ASSERT(pPointer);
 //some instructions 

}

For the trapping of strange values in "switch" and "if" operators.

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!

}

For the values assertion

ASSERT(nSomeValue >= MinValue and nSomeValue <= MaxValue);
ASSERT(nOtherValue != 0);

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

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 so:

VERIFY( m_MyWnd.Create() );

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

Object verification and the ASSERT_VALID MFC macro

Using verify member of class is a wide-known technique for verification objects. If you have clear validate conditions for your object you can create and use the verify class member.

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;
  pm_m = m;
 ASSERT(Verify());
}

Most MFC classes are children of CObject. It has the AssertValid virtual function that uses for verification. If a class has the implementation of this function it is called by 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.

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 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 VC++ IDE uses "output" window (View-Output menu point). For debugging output you can use TRACE operator that has the same format as the printf STDIO function.

Here are some examples :-

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

Links

(C) Alex Rest, 2003

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here