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