Common C++ Pitfalls and ways to avoid them

by - Blake Madden

 

Constructors and Destructors

This isn't necessarily a pitfall, but it is certainly worth mentioning that although class (and structure) constructors and destructors are functions, they are quite different from any other function and you should know the difference.  Here is a list of interesting points about these two special types of functions.

1.  Neither constructors nor destructors have return types (not even void).

2.  A destructor cannot take arguments (not even void).

3.  A destructor cannot be overloaded.

4.  Both constructors and destructors are called implicitly, so you never need to call them yourself.

5.  Constructors cannot be declared virtual.

6.  Both constructors and destructors must have the same name as its class (structure), except  a destructor  has a tilde (~) in front of it.

7.  Even if you don't explicitly write a constructor and destructor for a class, the compiler will  write default ones for you (because a class must have both).

 

The fall-through switch statement

The problem:  When a switch statement evaluates its cases and one of its cases are found to be true, then of all the remaining events listed in the rest of the switch block will execute unless a break is found. 

Here's an example:

 

int Number = 1;

switch (Number)

{

case 0:

cout << "Number is zero";

case 1:

cout << "Number is one";

case 2:

cout << "Number is two";

}

 

Logically, since Number is 1, then the output would be Number is one;  However, Number is oneNumber is two  is the output.  Without the break keyword, the remaining events fall through and execute until either a break is found later on or the switch block ends.

 

The solution: Here is the correct switch block:

 

switch (Number)

{

case 0:

cout << "Number is zero" <<endl;

break;

case 1:

cout << "Number is one" <<endl;

break;

case 2:

cout << "Number is two" <<endl;

break;

}

Now it will behave the way the you expected it to.  Those coming from Visual Basic will note that this isn't necessary in a select case (VB's equivalent to a switch case), and this could be an understandable pitfall.  Sometimes (although rarely) you may wish for your case events to fall through--which in that instance you would pull out the breaks.  However, most of the time you wouldn't, and you defineately want to watch out for this.

 

The Null Terminator

When using a C-style string (a char array), don't forget to include the null terminator, which is the zero character added to a char array indicating that it has reached its end.

 

Here's an example:

 

char Name[4] = {'J','o','h','n'};

 

Although there are four chars in the Name array and there are four letter in the name "John," this is incorrect because the string wasn't terminated. 

 

Here's the correct way:

 

char Name[5] = {'J','o','h','n','0'};

 

Now the last letter is zero and terminate the string.  This way, when function like strcat or strcpy look at this car array, it will know when the string ends and when it should stop reading it.

 

An alternative to this is to use the STL's string class:

string = "John";

 

Rogue Pointers (Arrays)

 

C++ doesn't support boundary checking on its arrays, and this leads to some of the worst bugs that your program could ever have.

 

Here's an example:

 

char Name[5];   //indexes are 0-4 (5 units in this array)

 

for (int i = 0; i = 5; i++)

{

Name[i] = "b"

}

 

What happens here is that the loop runs six time (not five) and Name[5] has the letter b written to it.  What is Name[5]?  It's not part of your array, but rather another address in your memory that something else was probably using.  The reason that C++ allows this while other language catch this for you (i.e. Visual Basic) is because the additional error trapping that would be necessary would make C++ much slower.  This additional overhead was deemed unacceptable and was left as is (the way C handled it).  You could write dianostic member functions inside of your classes to help avoid this, but bear in mind the overhead that it may involve.  The best advice here is to watch loops and functions that act on your arrays, and perhaps even use constants in your array parameters instead of numbers that are easy to forget:

 

const MAXARRAY = 20;

 

char Name[MAXARRAY ];   //indexes are 0-4 (5 units in this array)

 

for (int i = 0; i < MAXARRAY ; i++)

{

Name[i] = "b"

}

If this for loop was further down in your code, then keeping track of a few constants is much easier then trying to remember a bunch of meaningless numbers.

Add your tutorials to this site Mail Me

Click Here!

1