How To Stay Sane with Modern C++
Table of Contents
C++ grows very fast! For example, the number of pages of the C++ standard went from 879 pages for C++98/03 to 1834 for C++20! Nearly 1000 pages! What’s more, with each revision of C++, we get several dozens of new features. Have a look at my blog post with all C++17 features, it shows 48 items, and my C++20 reference card lists 47 elements!
Do you need to learn all of that stuff to write good code?
How to stay sane in the C++ world today?
You probably know that C++ is a complex language. As I’ve found, there’s even a whole Wiki page about the criticism of Cpp. Modern C++ adds even more stuff to the package!
Here’s the full data about the page count in the specs that I’ve mentioned before:
- C++98/03 - 879, N1905, Oct 2005
- C++11 - 1324, last draft, N3337, Jan 2012
- C++14 - 1368, last draft, Nov 2014
- C++17 - 1586, draft, N4606
- C++20 - 1834, draft, N4861
It looks like C++17 is almost ~80% ‘larger’ than C++98/03, and the latest draft of C++ has nearly 1000 pages more than C++03. You can complain about added complexity and that it’s hard to learn all of those things. But is this so terrible? What can you do about the whole situation?
This post was motivated by some stories recently found::
- HN: C++11 FAQ
- r/programming, lvalues and rvalues used to be simple things. Now, only a handful of people truly understand all facets of C++ value categories.
- Why I don’t spend time with Modern C++ anymore | Hacker News
- r/programming, Modern C++ Features – decltype and std::declval
- Reading this sub for an hour has made me crazy. : cpp
- ABI: Now or Never : cpp
But to have a balance and something positive, there’s also a discussion like this one:
Maybe it’s not that bad after all? :)
First, let’s see some problems that you might bump into in C++.
To name a few:
- Too slow pace
- Too fast pace
- Confusion/complexity of features
- Slow compilation Times
- Lack of dependency management
Let’s look at those in more detail.
Too slow pace
In 2017 we got C++17. While it’s great, that we get a new standard every three years, a lot of developers complained that the new version is not what everyone waited for.
A lot of features: like concepts, modules, ranges, co-routines, … were not accepted and we need to wait at least three more years to get them in the spec.
Now, in 2020, we have C++20 ready, and those significant features are shipping with compilers! Yet, we can complain that contracts are not present, reflection, executors or networking is still being discussed. They might appear in C++23 or even later.
It looks like some features are slower to accept… .and there will always be something to complain.
Too fast pace
As usual, we might have two contradicting opinions here. Although for some people the pace is slow, for others it’s hard to keep up with the changes.
You’ve just learned C++11/14… and now you need to update the knowledge with C++17, and then C++20 is along the way. Three years is not that short time, but bear in mind the compiler conformance, company policies, team guidelines might walk at a different pace.
Do your companies update to the most modern C++ version immediately or wait a couple of years?
Confusion / complexity of features
Just read that comment:
I love c++. It’s my go to language, but you have to admit its ‘hodge podge’ implementation of value types is bizarre at best. Most programmers including me prefer simple well-defined language constructs over bizarre and over complicated grammar. I’m not a computer language lawyer. I’m a programmer.
Is C++ clear in every aspect? Probably not…
Here are some topics that might be hard to understand and might cause confusion among programmers:
The principle of move semantics are quite clear: instead of copying try to “steal” the guts of the managed resources, and you should get a nice performance boost. But the devil is in the detail.
I don’t write a lot of generic code, so, fortunately, I don’t have to think about move semantics all the time. But I was quite confused when I bumped into move and const - see my last article on that. I don’t believe every C++ will understand the rules here. Especially that you now need to remember about six default operations generated by the compiler: default constructor, destructor, copy constructor, move constructor, assign operator and move assignment operator.
Rvalues/xvalues/prvalues… myValues, fooValues
The last ones are made up… but still having all of the value categories is overwhelming!
In C (or C++98/03) you just had to know lvalue vs rvalue, now it’s a bit more subtle.
Still, the question is if you need to know it by heart?
Some good comments:
It is complicated, but not on a daily basis. Can this value be addressed ? can it be copied ? can it be moved ? Should it be moved ? There is very few situation where you want to actively to be very specific and need a full understanding. ( templated library writing, hot paths, etc).
Most of the time C++ is not more complicated than java or something. Sadly this is lost on most people. C++ may be the most complex language out there but you can write very good code without caring about the specific.
BigObject o = getBigObject();
Templates (and Template deduction)
I was quite lost when I saw all the changes for C++17; there are so many details about templates!
The same situation happens in C++20, where we have a significant and long-awaited improvement: concepts - which revolutionise C++!
Yet, if you want to learn templates, it might be overwhelming at first.
With the growing list of new features, it might be tempting to “start from scratch” and fix old issues in the design of C++. But the principle of the language is that it cannot break old code, so that why the Committee is so restrictive and don’t like to change the way how features are introduced.
There’s no right answer to this issue, but in any way, it’s good to have a well-discussed topic rather than a rushed move.
Lack of Dependency Management Tools
We can complain that C++ is not “shipping” with a cool dependency management system. But the reality is that it might not happen in the foreseeable future. Having a “standard” package manager is a tough choice, especially that it would have to handle so many different platforms and systems where C++ is available.
Not Safe Enough
Roughly 70% of all serious security bugs in the Chrome codebase are memory management and safety bugs, Google engineers said this week.
And similarly for Microsoft. Since most of the code is C or C++, then everyone blames C++ for not being safe enough.
What are your main problems with the language?
So far, we’ve discussed some problems… so how to live with them? Is there a chance to solve those issues?
How to Stay Sane
There’s no perfect programming language; every one of them has some issues. Here are my suggestions on how to cope with the problems of Modern C++:
- Stay positive
- Use best guidelines
- Use best tools
- Stay up to date
- Don’t open the hood
- Use what you need
- Incremental change
- Last resort: your old code is still safe and compiles
Stay positive, the language is evolving
No one wants to write code using old syntax and constructs. We’ve already seen a lot of complaints about old C++ before C++11. It took almost 13 years (counting from major C++98, not including minor C++03) to came up with the major version: C++11. Now we can be happy that we get back on track, and every three years there will be some changes. At the end of the day, you cannot say that your language is dead and old.
While some of the features are huge and can bring confusion or more things to learn, things are more straightforward than harder:
- Most of those 1000 new pages that were added after C++03 are for the Standard Library. This means that you have more helpers and sub-systems you can use, without the need to find third-party libraries. That definitely makes your life easier.
- For move semantics, you can rely on library types as they will do the right job for you. For example, you can now safely return
std::vectorand be sure that it might be moved or even elided and no extra copy will be needed.
- For templates, it’s getting easier and easier. Concepts make code safes, without tricks like SFINAE. What’s more, we have
autowhich makes generic code even simpler (almost like a regular code).
- As for the safety: Hava look here at automatic tools for the safety profile for C++ Guidelines. New safety rules in C++ Core Check | C++ Team Blog. We can expect new and better tools that perform code analysis or even instrumentation to find potential safety issues as fast as possible. Or here Closing the Gap between Rust and C++ Using Principles of Static Analysis - Sunny Chatterjee - CppCon
If you’re lost with many different aspects of C++ code, then you should reach for C++ Core Guidelines. It’s created by the community of dedicated and passionated C++ developers, and the main editors are Herb Sutter and Bjarne Stroustrup.
And here’s a nice looking web site:
Just type the issue you are facing (for example
return value), and you can easily find the advice - for example: Guideline: Return values
Using those guidelines will save you a lot of time, and you can learn some good patterns very quickly.
And the tools as well!
Thanks to Clang and also improved development speed in other platforms, we get tools like:
- Clang Tidy (previously clang- modernise)
- Clang Format
- Clang Static Analyzer
- Clion/Resharper C++
- VisualStudio - tools like C++ Core Checker
- PVS Studio
- Clang Power Tools for Visual Studio
- New C++ Core Check Rules | C++ Team Blog
- C++ Core Guidelines checker reference | Microsoft Docs
- Introducing vcperf /timetrace for C++ build time analysis | C++ Team Blog
- New safety rules in C++ Core Check | C++ Team Blog - C++ as safe as Rust?
Or see my article about the other tools: C++ Ecosystem: Compilers, IDEs, Tools, Testing and More
While it’s not super great as for other languages (mostly Java-based or .NET based), it’s getting better and better. Bear in mind that because of the complex C++ grammar, it’s tough to implement tools that analyse the code on the fly.
Try to stay up to date
C++ community is very much alive. There are many blogs, books, conferences… and there’s even a chance a local community is in your city!
For a start, I suggest going to isocpp.org the central place for all of the events/news/articles. Then you might check Meeting C++ and info about local C++ groups. There’s also reddit/cpp where you can read some of the best C++ stories.
And there’s also a CppCast - a weekly podcast for C++ developers.
And remember about books like:
- The C++ Programming Language, 4th Edition 4th Edition
- Effective Modern C++
- Programming: Principles and Practice Using C++
- Discovering Modern C++: An Intensive Course for Scientists, Engineers, and Programmers
- A Tour of C++ (C++ In-Depth Series) 2nd Edition
You can also take a look at the list of suggested C++ Resources:
Too many details? Just don’t open the hood.
One of the reasons C++ has so much power is that it allows you to implement code very close to the metal. You have control over all of the details, memory layout, performance optimisations, etc, etc… At the same time, such abilities increase the complexity of the language.
Still, if you don’t need to go that far, you can stay at a relatively higher level of abstraction.
For example, there’s no need to write an optional type because you can use
std::optional from the Standard Library. If you don’t want to bother with lowe level and error-prone unions you should see
std::variant which is a safe alternative.
Use what you need
C++ is a multi-paradigm language; you can use it in many different ways. Recently, I’ve read an interesting comment that said that a Cpp programmer might for years do very well without touching advanced stuff like template metaprogramming or even exceptions. This heavily depends on the code style of the project.
Even such companies like Google limit features of C++, for example, they don’t use exceptions.
This is a bit of repetition, but if you’re not a library developer, you might not get into troubles with custom move operators or move constructors. Similarly, advances metaprogramming stuff might also not be a crucial part of your code.
If you start from scratch or have a small code base then going to C++11/14 should be relatively easy. What about million-line of code, code that was created 20 years (or more!) ago?
Just do it step by step.
At least for the new code, you should start using Modern C++. Moreover, by applying “The Boy Scout Rule”, you can improve the surrounding code that you touch.
This will probably result in some mixed code, but still, it’s better than staying with the legacy style only.
Last resort: your old code will still compile!
One of the reasons why C++ specs are getting larger and larger is that the language is backward compatible. So the committee usually introduces new features, but rarely remove the old stuff. So… your code can still compile. If you don’t want to move and use newer things, then you can stay with your current style.
From time to time you’ll get some warnings about deprecated stuff or removed features (like
auto_ptr in C++17), but even in that case, you can switch the compiler to target some older C++ standard.
This article is partially a rant, partially a ‘glorification.’ I try to see the problematic sides of the language and its evolution process and some positive signs as well.
While we can complain about the complexity, pace of changes, etc, I think we cannot say that the language is dead. That’s a good thing! :)
I don’t think you have to rapidly chase the new features and immediately rewrite your existing code. Just try to stay up to date with news, use the features that really improve your work and gradually your code should improve and be more ‘modern’ (however, can that be defined - see meetingcpp article on that).
- What’s your approach when adopting new features from C++11/14/17/20?
- What’s your main problem with C++?
- Do you use modern C++ in your work?