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.