
According to Hoyle...
C++0x Part 2: A Step Forward
macCompanion
November 2009
by Jonathan Hoyle
jonhoyle@mac.com
http://www.jonhoyle.com
Last month, we began examining the upcoming changes to the
C++ programming language. In
it we discussed the evolution of C++ and where it is today. Having examined
C++'s past and the present, we move on to describe its future. However,
before doing that, we take one look back for a cautionary tale.
The Cautionary Tale of EC++
From 1996-1999, a consortium of Japanese embedded systems tool developers
(including
NEC,
Hitachi,
Fujitsu and
Toshiba)
were putting together a proposal for a language subset of C++. This
subset would essentially be C++ with a number of language features removed,
which (they assumed) was too complicated and could hurt performance. The
features targeted for removal included:
multiple inheritance,
templates,
exception handling,
RTTI,
the new cast operators, and
namespaces. This
new language subset would be called
Embedded C++,
or EC++for short.
To the surprise of the consortium members, the EC++ compilers were not
only no faster than their C++ cousins, but in some domains, EC++ was actually
slower! C++ founder Bjarne Stroustrup later explained that templates
were used in much of the Standard Library to improve performance, and
their removal put EC++ at a disadvantage. Upon hearing this, the
dazed members of the EC++ consortium scrambled to put together a new proposal:
Extended EC++, which was simply EC++ with templates put back in.
When the Extended EC++ compilers became available, they were once again
put to the test against their C++ cousins. Tothe consortium's continued
bewilderment, once again the performance gains relative to C++ turned
out to be negligible. Part of the problem was the consortium's ignorance
of C++'s
Zero Overhead Principle:
"what you don't use, you don't pay for". After this final embarassment,
ISO refused to endorse any of the EC++ proposals.
In 2004, inspired by the EC++ debacle, the C++0x committee called for a
Performance Technical Report
to determine which features of the C++ language which truly had the greatest
penalties in performance. As it turned out, there were only three
areas in which there was any measurable performance
issues:
- Free Store: new and delete
- RTTI: dynamic_cast<> and typeid()
- Exceptions: throw and catch
Memory allocation and deallocation
turned out to have the largest impact on performance; however, it is unlikely
that you would want to use a language which did not dynamically allocate
memory. As for RTTI and exception handling, many compilers have
switches allowing the developer to disable these, if desired. Modern
compilers often have greatly optimized their implementations of exception
handling, making RTTI the only outlier. In any case, with the Zero
Overhead Principle in place, simply not using a C++ language feature
is no different than having it removed from the language itself.
As for EC++,
Stroustrup is quoted as saying:
"To the best of my knowledge EC++ is dead, and if it isn't it ought to be."
Is there a moral which can be gleaned from this decade old lesson? Only
that knee-jerk reactions tend to result in unexpected consequences. The
whole Embedded C++ fiasco could have been avoided with only a little bit
of time and effort to properly research the problem. So now (finally),
onto some changes coming in
C++0x ...
Embarrassments, Fixes & Improvements
Although the
C++ standard in 1998
was an astounding achievement, there were a small number of flaws which
remained. Some of these were simply due to oversight; others were
known, but there had not been sufficient agreement by the Standards Commitee
as how to resolve them, within bthe time permitted. Bjarne Stroustrup
described some of these as embarrassments, particularly when trying to
explain them to novices. With the upcoming version of C++0x, many
are finally being addressed. Such improvements include:
vector<vector<int>> x; // Finally, legal!
vector<double> x = { 1.2, 2.3, 3.4 }; // Initializing STL containers
stronger typing of enum's // Enumerated types remain in their scope
extern-ing of template's // No duplication across translation units
If you are not familiar as to why any of the above caused errors, you
needn't even bother to understand why. They are problems that are
going away in C++0x. I will delve into the first item only (Stroustrup's
biggest example of "embarrassment"), to give you a flavor of the problem. The
flaw lies simply with the fact that C++98 parses the ">>" portion
of vector<vector<int>> x; as
a right shift operator and generates an error; C++0x fixes this. One
of the reasons this took so long is that ANSI/ISO committee members were
very hesitant to put in silent changes in the specification. A silent change
is one which would keep the meaning of some C++ code with generating an
error. Surprisingly, the reinterpretation of ">>"
within templates can indeed yield a silent change, as this example below shows:
template<int I>
struct X
{
static int const x = 2;
}
template<>
struct X<0>
{
typedef int x;
}
template<typename T>
struct Y
{
static int const x = 3;
}
static int const x = 4;
cout << (Y<X<1>>::x>::x>::x) << endl; // C++98 prints "3"
// C++0x prints "0"
ANSI/ISO C99 Synchronization
The ANSI/ISO C specification was
updated in 1999 with
a number of improvements in the language. Many of these improvements
were simply acquiring behavior which was already legal in C++, but seemed
to make sense for C as well. Other changes were not part of C++,
but the ANSI/ISO C++ committee in turn saw some of these features as valuable
and are rolling these into the C++0x specification. These include:
__func__ // returns the name of the function
long long // extended integral type, eg: 64-bit
int16_t, int32_t, intptr_t, etc. // fixed-sized integers
Hex floating point types, eg: double x = 0x1.F0;
Complex versions of some math functions, such as arcsin(), arccos(), fabs(), etc.
Variadic macros, that is macros taking a variable number of arguments, such as:
#define S(...) sum(__VA_ARGS__)
With these changes, C++0x is modernized for the upcoming decade.
Coming Up
C++0x Part 3: Making Coding Easier
C++0x Part 4: Smart Pointers
C++0x Part 5: Rvalue References
C++0x Part 6: Final Thoughts