Professional C__ - Marc Gregoire [453]
Despite the obvious importance of debugging, it is rarely given enough attention in courses and books. Debugging seems to be the type of skill that everyone wants you to know, but no one knows how to teach. This chapter attempts to provide you with concrete guidelines and techniques for debugging even the most galling problems.
The contents include an introduction to the Fundamental Law of Debugging and bug taxonomies, followed by tips for avoiding bugs. Techniques for planning for bugs include error logging, debug traces, and asserts. The chapter concludes with specific tips for debugging the problems that arise, including techniques for reproducing bugs, debugging reproducible bugs, debugging nonreproducible bugs, debugging memory errors, and debugging multithreaded programs. The chapter concludes with a step-by-step debugging example.
THE FUNDAMENTAL LAW OF DEBUGGING
The first rule of debugging is to be honest with yourself and admit that your program will contain bugs. This realistic assessment enables you to put your best effort into preventing bugs from crawling into your program in the first place while you simultaneously include the necessary features to make debugging as easy as possible.
The Fundamental Law of Debugging: Avoid bugs when you’re coding, but plan for bugs in your code.
BUG TAXONOMIES
A bug in a computer program is incorrect run-time behavior. This undesirable behavior includes both catastrophic bugs and noncatastrophic bugs. Examples of catastrophic bugs are program death, data corruption, operating system failures, or some other similarly horrific outcome. A catastrophic bug can also manifest itself external to the software or computer system running the software, for example, a piece of medical software might contain a catastrophic bug causing a massive radiation overdose to a patient. Noncatastrophic bugs are bugs that cause the program to behave incorrectly in more subtle ways, for example, a web browser might return the wrong web page, or a spreadsheet application might calculate the standard deviation of a column incorrectly.
There are also so-called cosmetic bugs, where something is visually not correct, but otherwise works correctly. For example, a button in a user interface is left-enabled when it shouldn’t be, but clicking it does nothing. All computations are perfectly correct, the program does not crash, but it doesn’t look as “nice” as it should.
The underlying cause, or root cause, of the bug is the mistake in the program that causes this incorrect behavior. The process of debugging a program includes both determining the root cause of the bug and fixing the code so that the bug will not occur again.
AVOIDING BUGS
It’s impossible to write completely bug-free code, so debugging skills are important. However, a few tips can help you to minimize the number of bugs:
Read this book from cover to cover: Learn the C++ language intimately, especially pointers and memory management. Then, recommend this book to your friends and coworkers so they avoid bugs too.
Design before you code: Designing while you code tends to lead to convoluted designs that are harder to understand and are more error-prone. It also makes you more likely to omit possible edge cases and error conditions.
Use code reviews: At least two people should look at every line of code that you write. Sometimes it takes a fresh perspective to notice problems.
Test, test, and test again: Follow the guidelines in Chapter 26.
Expect error conditions, and handle them appropriately: In particular, plan for and handle out-of-memory conditions. They will occur. See Chapter 10.
Last, and probably most important, use smart pointers to avoid memory leaks: See Chapter 21 for details.
PLANNING FOR BUGS
Your programs should contain features that enable easier