Tips and Traps for young programmers






3.50/5 (24 votes)
Apr 25, 2003
3 min read

59284
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?
- 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.
- Using break points and trace you can easily find non-initialized pointers.
- 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?
- 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
- My other articles, demo project and collection of interesting C++ links you can find here: http://www.brigsoft.com/edu
- My software is here: http://www.brigsoft.com.
(C) Alex Rest, 2003