C++ vs. C
The C++ programming language brings improvements over its predecessor C, but fans of other languages point out that C++ is still not perfect. Over a decade after the 1998 standardization of the C++ programming language, the C++ vs. C debate continues.
Compared to C, C++ has a bunch of new language features with little or no runtime overhead because they are translated to code equally as efficient as the equivalent C code:
- function overloading
- STL, the part of the C++ standard library with containers and algorithms
- references, needed by operator overloading
A few features are as efficient as C yet still rawther deceptive and easy to misuse because the "simple" syntax hides how much code is actually being generated:
- operator overloading, when compared to ordinary function-call syntax
virtual(polymorphic) methods, when compared to C function pointer tables, especially the pure virtual method's undefined behavior that some compilers may implement as an exception
- templates instantiated several times, when compared to using the preprocessor to instantiate multiple copies
class is a
struct whose first member is
That's the only difference.
C++ also has some features requiring possibly expensive runtime library support:
Templates have a couple drawbacks:
- Type names in error message become far more difficult to interpret. Common implementations may expand a template type name fully in diagnostic messages even if the source code accesses the type through a
typedef. For example, an error message involving the
std::stringtype is likely to provoke this reaction: "
basic_string? I'm using C++, not BASIC! And what the fsck is
char_traits?" (True, implementations are not the language, but a language is only as good as its best free implementation.)
- Programmers can lose track of for how many different type combinations they have instantiated a template, causing code size to balloon. There is a common extension called
extern templateallowing for explicit instantiation, but it's not in C++98, and not all compilers support it.
throw) also have a couple drawbacks:
- Though exceptions have little to no runtime speed penalty in a modern C++ compiler, the size of the required library support might cause a problem on embedded or handheld devices with less than about a megabyte of RAM.
- C++98 has no counterpart to the
finallykeyword of Java and Python. True, there isn't as much need for
finallyin C++ as in languages that rely on a garbage collector, given the idiom of allocating resources in constructors that C++'s deterministic destruction allows. But a method often still needs to restore the object's fields to a consistent state before eating or rethrowing the exception. C++0x addresses this by letting the programmer build a scope-guard with
std::shared_ptrand lambda expressions.
On platforms without virtual memory, a program must be aware of possible out-of-memory conditions.
The STL allows passing an allocator to all containers, but most implementations appear to exhibit undefined behavior when
allocate() returns 0 like new(std::nothrow) does.
I've been told one STL implementation can be built with
nothrow in mind: STLPort.
EA Games created an out-of-memory-aware allocator.
<iostream> library is another divisive issue.
It was envisioned as a type-safe alternative to
<cstdio>, but implementations are hairy, bloated, and inefficient.
This goes double if you have to use a statically linked implementation of the C++ standard library, either because the operating system provides no C++ standard library (e.g. handheld video game systems) or because your compiler's C++ ABI differs from that of the operating system publisher's own development tools (e.g. MinGW).
Hello World programs with
-Os and statically linked libstdc++ in one version of MinGW resulted in 5,632 bytes for
<cstdio> but 266,240 bytes for
A devkitARM project targeting Game Boy Advance had similar results: 5,156 bytes for C-style I/O and 253,652 bytes for
<iostream>; even removing some unreachable code with
-Wl,-gc-sections couldn't get it below 180,032 bytes.
(For comparison, the GBA's main RAM is 262,144 bytes.)
These tests are with GNU libstdc++, which initializes date, time, and money aspects of a locale for each stream even if the program never shifts a date, time, or money object into the stream.
This is because it was conceived before templates and instead uses virtual inheritance and "facets", which C++ implementations can't optimize well.
Some third-party C++ standard library implementations such as uClibc++ are designed for space efficiency and leave out features such as locale support that aren't as useful in small-memory systems.
Yet some C++ fanboys claim that anything using good old
<cstdio> instead of new-fangled
<iostream> isn't in the spirit of C++, whatever that means. They cling to item 2 in the second edition of Scott Meyers' Effective C++, which promotes
<cstdio>, and ignore item 23 of his sequel ("consider alternative libraries"). It appears that Meyers eventually recognized that
<iostream> is imperfect and removed item 2 from the third edition.
"As an embedded programmer, I shun C++." -- Arlet, 2011-11-01