This is a mini-rant, a short essay refuting a common misconception among users of an Internet forum. If you think this essay is FUD, feel free to explain why on the essay's talk page.
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:
new(std::nothrow)
virtual
methodsA 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:
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 exceptionPROTIP: A class
is a struct
whose default access is private
.
That's the only difference.
If you specify access before any members, class
and struct
mean the same thing.
C++ also has some features requiring possibly expensive runtime library support:
Templates have a couple drawbacks:
typedef
. For example, an error message involving the std::string
type 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.)extern template
allowing for explicit instantiation, but not all compilers support it yet.Exceptions (throw
) also have a few drawbacks:
finally
keyword of Java and Python was not added until C++11. True, there isn't as much need for finally
in 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. A C++11 programmer can build a scope-guard with std::shared_ptr
(or gsl::finally
[1]) and 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.[2][3]
EA Games created an out-of-memory-aware allocator.
The <iostream>
library is another divisive issue.
It was envisioned as a type-safe alternative to <cstdio>
, but implementations are hairy, convoluted, 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 <iostream>
.
A devkitARM project targeting Game Boy Advance had similar results: 5,156 bytes for C-style I/O and 253,652 bytes for <iostream>
.
(This is expected; Thumb and x86 have comparable code density.)
Even removing some unreachable code with -Wl,-gc-sections
couldn't get the GBA project 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.[4]
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.
In fact, one C++ advocate claims that comparing memory usage of C++ to C by targeting a sub-megabyte platform with GNU libstdc++ sets up a huge straw man.[5]
Yet some C++ fanboys claim that anything using good old <cstring>
and <cstdio>
instead of new-fangled <string>
and <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 <iostream>
over <cstdio>
, and ignore item 23 of his sequel ("consider alternative libraries").
Meyers did remove item 2 from the third edition, evidently recognizing that <iostream>
is far from perfect.
Someone who knows a few people on the standards committee thinks Boost.Format is idiomatic and <iostream>
is just idiotic.
"As an embedded programmer, I shun C++." -- Arlet, 2011-11-01
Some who take the time to truly understand C find that C is often the right language for the job. C compiles to much smaller WebAssembly than idiomatic C++ does. The designated initializer syntax introduced in C99 is an unfortunate omission from C++[3] prior to the forthcoming C++2a standard. The eighteen different types of object initialization in C++ are "bonkers".[4]
Categories: Mini-rants