Chapter 1. Where Do C++ Bugs Come From?

The C++ language is unique. While practically all programming languages borrow ideas, syntax elements, and keywords from previously existing languages, C++ incorporates an entire other language—the programming language C. In fact, the creator of C++, Bjarne Stroustrup, originally called his new language “C with classes.” This means that if you already had some C code used for whatever purpose, from scientific research to trading, and contemplated switching to an object-oriented language, you’d need not to do any work of porting the code: you’d just install the new C++ compiler, and it would compile your old C code and everything would work the same way. You might even think that you’d completed a transition to C++. While this last thought would be far from the truth—the code written in real C++ looks very different from the C code—this still gives an option of a gradual transition. That is, you could start with existing C code that still compiles and runs, and gradually introduce some pieces of new code written in C++, mixing them as much as you want and eventually switching to pure C++. So the layered design of C++ was an ingenious marketing move.

However, it also had some implications: while the whole syntax of C was grandfathered into the new language, so was the philosophy and the problems. The C programming language was created by Dennis Ritchie at Bell Labs around 1969-1973 for the purpose of writing the Unix operating system. The goal was to combine the power of a high-level programming language (as opposed to writing each computer instruction in an assembler) with efficiency: that is, the produced compiled code should be as fast as possible. One of the declared principles of the new C language was that the user should not pay any penalty for the features he does not use. So, in pursuit of efficient compiled code, C did not do anything it was not explicitly asked to do by the programmer. It was built for speed, not for comfort. And this created several problems.

First, a programmer could create an array of some length and then access an element using an index outside the bounds of the array. Even more prone to abuse was that C used pointer arithmetic, where one could calculate any value whatsoever, use it as a memory address, and access that piece of memory no matter whether it was created by the program for this purpose or not. (Actually, these two problems are one and the same—just using different syntax).

A programmer could also allocate memory at runtime using the calloc() or malloc() functions and was responsible for deallocating it using the free() function. However, if he forgot to deallocate it or accidentally did it more than once, the results could be catastrophic.

We will go though each of these problems in more detail in Part II. The important thing to note is that while C++ inherited the whole of C with its philosophy of efficiency, it inherited all its problems as well. So part of the answer to the question of where the bugs come from is “from C.”

However, this is not the end of the story. In addition to the problems inherited from C, C++ introduced a few of its own. For instance, most people count friend functions and multiple inheritance as bad ideas. And C++ has its own method of allocating memory: instead of calling functions like calloc() or malloc(), one should use the operator new. The new operator does more then just allocating memory; it creates objects, i.e., calls their constructors. And in the same spirit as C, the deallocation of this memory using the delete operator is the responsibility of the programmer. So far the situation seems to be analogous to the one in C: you allocate memory, and then you delete it. However, the complication is that there are two different new operators in C++:

MyClass* p_object = new MyClass();  // Create one object
MyClass* p_array = new MyClass[number_of_elements]; // Create an array

In the first case, new creates one object of type MyClass, and in the second, it creates an array of objects of the same type. Correspondingly, there are two different delete operators:

delete p_object;
delete [] p_array;

And of course, once you’ve used “new with brackets” to create objects, you need to use “delete with brackets” to delete them. So a new type of mistake is possible: the cross-use of new and delete, one with brackets and another without. If you mess up here, you can wreak havoc on the memory heap. So to summarize, the bugs in C++ mostly came from C, but C++ added this new method for programmers to shoot themselves in the foot, and we’ll discuss it in Part II.

Get Safe C++ now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.