The term “Modern C++” is often used interchangeably with “Code using the new C++ standard”. Here, “new” may be anything from C++11 to C++17 or even whatever is available of C++20 right now. I think that modern C++ is more and something different than just adding that
What is modern?
If we look up definitions for the word “modern” on the web, one of the first is by Merriam-Webster. The two parts relevant for “Modern C++” are:
2 : involving recent techniques, methods, or ideas : (up-to-date) modern methods of communication
3 capitalized : of, relating to, or having the characteristics of the present or most recent period of development of a language – Modern English
When it comes to techniques, methods, or ideas, there’s much more than just new language features. Often, those new features support or enable such techniques, but others have been around for quite some time. Regarding characteristics of the development of the language, those characteristics arise from how we use the language. This is about how we put features – old and new – together, which is much more than just what is a valid C++ program and what comes with the standard library.
One could argue that the features that have been around since ’98 are not part of modern C++, because they have been around for so long. However, we have to keep in mind that those that are vocal in the C++ community and talk or write about “Modern C++” typically are part of the early adopters. A huge number of people still write, learn, and even teach good old 90’s “C with classes”, which makes many methods that are not used in that style part of Modern C++.
Beyond new features
So what are those things available in C++98 that I think belong to the “Modern C++” category? Here’s a (non-exhaustive) list of a few important features and ideas:
RAII stands for “Resource Acquisition Is Initialization”, or “Responsibility Acquisition Is Initialization”. While the name stresses the initialization part, the key aspect here is actually the destructor. Deterministic destruction is one of C++’s core features that sets it apart from most other languages. For many, it is the most important feature.
RAII can be used to reliably manage a plethora of things, like memory (e.g. in
std::string), file handles (
std::fstream), network handles, mutexes, database connections, but also things that are not exactly resources. If you ever have to do something and reliably undo it at the end of some scope or when some object lifetime ends, RAII is your friend.
I’ve seen lots of old code bases where functions would end in a mess of manual cleanup. That cleanup won’t be reached in case of exceptions, so RAII is your friend here. Even if you have exceptions turned off, early returns can clean up your code considerably, but not if you still have that cleanup to do.
So, RAII definitely belongs to modern C++ – even if it has been available since the very beginning.
The idea of strong typing has been all the rage recently. In the old days, every ID, size, Zip code, price etc. was just an int or double or another arithmetic type. That they are compatible with other, completely unrelated values that happen to share the same type was a pity and a source of bugs, but what can we do? At least the compiler doesn’t silently cast numbers and arrays to strings!
It turns out that with C++’s type system and the zero overhead abstractions* brought to us by the compiler, we can do a lot. Simply create different ID types, ZipCode types, size types (no, not typedefs, thank you) etc. If you’re interested, watch one of the talks by Björn Fahller, Jonathan Boccara or Jonathan Müller.
*(Even if such an abstraction is not entirely zero overhead, prove that the overhead hurts before you dismiss it.)
Except for some recent additions,
<algorithm> has been in the standard library from the very beginning. Yet if you look at code, people often prefer to handcraft their loops. Reasons range from ignorance of which algorithms are available to the belief that “templates are slow” (quite often without an explanation compared to what).
Things like template metaprogramming have been used in C++98. Compile-time logic can greatly reduce runtime complexity. Back in the day, it was not very convenient to use. Template syntax is quite different and much more involved than the features we got in the last standards. It’s more or less a second language we have to learn. However, things like tag dispatch and type traits are not too complex to use and write.
Yes, most type traits have been added to the standard library with C++11, but writing some for your own use cases is not that hard, and Boost had some general ones before C++11. I consider the use of compile-time logic as Modern C++ because it sets C++ apart from the omnipresent “C with classes”.
Modern C++ isn’t all about the new standards, it’s about the way we write our programs. Firstly, you can write a fairly modern C++98 style. Secondly, “C with classes and range based for” still isn’t modern C++. The language features and library additions help and enable us writing Modern C++, but they are not what makes our code Modern C++.
I’ve been wondering if 2011 C++ is the “new C” or “modern C.” Like the original C, it could adopt some of the newer things like string_view. My work with on-line code generation:
might work well with this version of things.
I wish RAII were more appreciated in the wider community of software developers.
Look at Webster’s definition of postmodern. Perhaps that term is closer to the usage of C++17 and its ilk.
Very enlightening peice. I too want to participate in the C/C++ conversation, even learn a thing or two as well.
I would assert that C++11 (and certainly C++17) is NOT the same language as C++98 or C++03. C++17 is to C++03 as C is to C with classes as Australian is to “King’s English”. They share the same foundation, but the languages in use and definition are in many ways actually incompatible (well Australian and “English” are probably more compatible 🙂 ).
It is unfortunate that we have not chosen a new name for the latest standards, because calling all of them “C++” just causes confusion. A well written C++17 using all the whiz-bang new features included has no hope of compiling or running on a C++03 compiler. The problem is that a large number of us are stuck on C++03 systems for a lot of reasons.
Well, that’s the same for anything that has additional features in newer versions: the lack of forward compatibility.
The other way round is more interesting: you can translate most of C++03 with a C++17 compiler because it still is the same language, but with new features. Yes, there are a handful of deprecations and in C++17 even removals, but those are only things that were not well usable in the past.
You should had a link to Mathieu Ropert’s blog entry “Modern C++ 03” .
Thanks, I wasn’t aware of that one.