C++ Annotated: March 2021
It is time for our monthly C++ Annotated and its companion, the No Diagnostic Required show!
As you might know, we deliver this digest in a few different forms. You can choose to read, listen, or watch our essential digest of this month’s C++ news.
- Read the digest published monthly on our blog (use the form on the right to subscribe to the whole blog).
- Subscribe to C++ Annotated emails by filling out this form.
- Watch the No Diagnostic Required show on YouTube. To be notified of new episodes, follow us on Twitter.
- Listen to our podcast – just search for "No Diagnostic Required" in your favorite podcast player (see the list of supported players).
- D2339R0 – “Contract violation handlers”
- P2332R0 – “Establishing std::hive as replacement name for the proposed std::colony container”
P2334R0 – “Support for preprocessing directives
- C++ on Sea
- C++ North
- And finally:
Watch the new episode of No Diagnostic Required below, or just keep reading this blog post for all the latest news!
Improving print logging with line pos info & modern C++
Print logging is still one of the most widely used methods for debugging and inspecting code. It’s also a place where we often use the macros in C and C++:
__LINE__. In this article, Bartlomiej Filipek discusses a few tricks on how to improve message scanning through the code in Visual Studio when the particular line is logged that way. A message in the predefined format
"%file(%line): %msg" guarantees you can double-click on the line in the Visual Studio output window and navigate to the source code.
What if you’d like to eliminate macros from the approach entirely? It’s now possible with
std::source_location in the C++20 standard! As of March 2021, std::
source_location is available in Visual Studio 2019 16.10, and GCC 11. The new library type has
constexpr calls for:
function_name. You can learn how to use it with this logging approach, in the same article.
If you are interested in the topic, feel free to read about Visual Studio Trace Points and check out what JetBrains CLion is capable of in terms of debugging techniques – such as non-suspending breakpoints, which allow you to log information without an actual break of the code execution.
GotW series by Herb Sutter: preconditions in some practical examples
The Guru of the Week series on Herb Sutter’s blog focuses on contracts – follow it for a lot of interesting information. We want to highlight one particular post from this series, which was published in March. This is the second part of a post dedicated to the preconditions topic, and it’s very practical with a “mental” exercise to find potential issues in the function declarations. How many ways could a caller of each function get the arguments wrong, but it would still silently compile without error? Herb discusses all the typical issues that may arise – the order of the arguments of the same type is wrong, the value passed is valid but out of range, and an invalid value is passed to a function.
It then goes into how you can improve and avoid some of the issues. You can group some of the parameters into a separate structure, use
std:: pair, use an encapsulated class with invariants preserved inside the constructors, or rely on post-C++20 contract preconditions. The blog post discusses when to use each of the solutions and gives a handful samples explaining the differences. For example,
is_sorted is much better as a function precondition, while
not_null seems better as a type.
Language and committee news, from Phil
Contracts make an appearance in this month’s ISO mailing, too. This time it’s a new discussion document, D2339R0 – “Contract violation handlers” . The discussion is around what is allowed to happen in the handler that is called when a contract is violated. This is one of the most hotly debated aspects of the contracts proposals, and one of the reasons they were pulled from C++ 20, so it’s no surprise it is being given meticulous attention. On the face of it, the three choices seem simple enough:
It ends in calling
- It ends by throwing an exception.
It returns normally (like a function that calls
The debate primarily swirls around the last two choices, which have been pretty polarizing, and get right to the heart of what a contract actually is. This paper doesn’t make any recommendations, but rather tries to capture all the important points from all sides. It makes great use of the body of use cases that the SG21 study group – set up to discuss contracts in the wake of their prior removal – has been putting together. This really helps to put some flesh on each point and consider them together, rather than each person focusing on their own use case and pushing for a solution that caters to that. It even points out where some of these cases are in conflict. There’s also a great summary of some of the, still surprising effects of undefined behaviour, including the ability to remove belts-and-braces runtime checks just because a contract violation handler is allowed to return normally! Even if you don’t usually tend to read standards committee papers, you might want to try this one, as it reads more like an interesting blog post.
The term “Design By Committee” is usually used in a pejorative sense, and there are certainly some downsides when it comes to evolving C++. But to paraphrase famous closet C++ programmer, Sir Winston Churchill, “Standards committees are the worst form of programming language governance – except for all the others.” Where the committee really excels is deliberating on what things should be called! Back in January, we mentioned a revision to the Colony proposal, and recapped what the Colony container type actually is, as that name doesn’t immediately tell you (although it does make sense in retrospect). Since then, the hive mind of LEWG have also taken issue with the name, noting that, as a metaphor, it breaks down in some ways at some levels. The subsequent hunt for a new name eventually settled on Hive. Interestingly, the one weakness noted in the new name is that bees don’t actually live in the cells of a hive. As it happens, I used to live in Hythe, Kent, in the UK, so the metaphor works just fine for me! In any case, the whole adventure is documented in P2332R0 – “Establishing std::hive as replacement name for the proposed std::colony container”.
This mailing also included a number of proposals that were actually from WG14 (the C Language Working Group). As part of the C/ C++ liaison effort, delegates from the committees are getting together to identify proposals in one committee that may impact the other. One of the ones that came up this time, and seems to have strong support on both sides, is P2334R0 – “Add support for preprocessing directives elifdef and elifndef”. While you can achieve the same result with
#ELSE and nested
#IFDEFs, today, it was felt that using the dedicated directives would be more readable and less surprising. Personally, I think they sound a little like elves from The Lord of the Rings.
Russian Coat-Check Algorithm and Ticket Maps
At the recent ACCU 2021 Online conference, Sean Parent did a presentation on “Better Code: Relationships", where he described the Russian Coat-Check Algorithm, an example of coding a case when the program holds some data that’s associated with an ID value, monotonically increasing. Sean used it to prove the idea that relationships (between data and code) are important for many aspects, like performance or memory allocations. The talk from the ACCU Online event has not yet been published, but you can already check out some measurements and benefits of the structure discussed in the talk in Sean’s slides.
Anthony Williams later implemented the algorithm described by Sean and wrote a small blog post on it. Check it out here, and also find a link to the GitHub repo with the full code.
Keep Code Consistent with Syntax Style in ReSharper C++
Some code style choices are the developer’s personal preferences, some are set by general, company, or project guidelines. It’s often not that important how the particular style is structured, but it is important that it’s consistent throughout the entire codebase. In this case, tooling comes into play! It can help configuring and enforcing the style on the codebase and that’s exactly what the new settings in ReSharper C++ 2021.1 are about!
What exactly is configurable as part of the Syntax Style? You can choose when to enforce the usage of the
auto keyword instead of the explicit type, whether
const is east const or west const styled, and whether to use nested namespaces and trailing return types. There are style settings for including directives, initialization, and braces. All these new settings and the ability to enforce the configured style on your codebase is described in the blog post. Note, the feature is only now available in ReSharper C++ 2021.1 Beta, but the new release is just around the corner.
Branch and Line and Statement code coverage in CLion
CLion 2021.1 EAP has recently introduced Branch code coverage. This seems like a good time to talk about the various code coverage types and how different tools calculate it. In general, there are 3 types of coverage:
- Line coverage – shows how many lines of your code (in %) were executed.
- Statement coverage – shows how many statements of your code (in %) were executed.
- Branch coverage – takes into account all the branches of each control structure.
GCC / gcov works in terms of line coverage, when compiled with the
--coverage flag. Which means, for “
return 0; int c;” you might get 100% coverage. This is not the case for LLVM / llvm-cov, which calculates statement coverage. This is something to remember when you use code coverage in CLion (which we call line coverage, by default).
The third type, branch coverage, was introduced recently. It takes into account all the branches of each control structure. For example, given an
if statement, it can tell you if both the
false branches have been executed. Interestingly there is again a difference between gcov and llvm-cov. GCC / gcov considers the compiler-generated branches when calculating branch coverage, while llvm-cov does not.
It seems like virtual conferences will be with us forever, but two upcoming conferences are doing two different things about it.
The first is this year’s C++ on Sea, which has now announced dates, June 30–July 2. As we mentioned in January, there is a change of structure to better suit the online format, with more of an emphasis on workshop-based training while still having a whole day of more “traditional” conference content. Early-bird tickets are available, the call-for-speakers is open, and Barbara Geller and Ansel Sermersheim have been announced as keynote speakers (that’s one keynote – two speakers!).
The second is a new conference – C++ North is planning to run in Toronto, Canada in 2022. We’ve been thrown plenty of curveballs, so there are still no guarantees, but we are hopeful we will finally be able to meet in person by then. We’ll give more details on this as they emerge.
And finally: Will we ever get rid of macros in C++?
This gets asked from time to time, and has just come up again on Reddit. Every revision on the standard adds another set of nails in the coffin of the C++ preprocessor. But that’s a big coffin! It does feel like we’re almost there. With
constexpr, in all its forms (including if constexpr), and
source_location really closing the gap in the last two standards, it doesn’t seem like there is much left. Some in the Reddit thread point out that token pasting will always be a hold-out (although reflection may have some answers there). If you look at the implementation of the
REQUIRE macro in Catch2 you’ll see that it expands to a lot of code. A lot of it could be replaced with a lambda – but this gets tried every few years, and so far the compile-time hit has always been too great! But surely that’s just a quality-of-implementation issue? If that could be done with
source_location as well, it should be possible to go macro free (with some sacrifices). In fact Kris Jusiak’s UT library does just that!
Of course being able to write code without using macros, and being able to take macros out of the language are two very different things. I think we’re still going to be stuck with macros for a long time to come.