C++17 attributes - maybe_unused, fallthrough and nodiscard
C++17 adds three new attributes for programmers to better express their intent to the compiler and readers of the code:
nodiscard. This is a quick post to outline what they do and why they are useful.
In case you aren’t familiar with the concept, attributes in C++ allow you mark functions, variables, and other entities with compiler-specific or standard properties. The standard attributes prior to C++17 are
noreturn (function doesn’t return),
deprecated (entity is going to be removed in a later version) and
carries_dependency (used for optimizing atomic operations). You mark an entity with an attribute like this:
With that out of the way, on to the new attributes!
[[maybe_unused]] suppresses compiler warnings about unused entities. Usually unused functions or variables indicates a programmer error – if you never use it, why is it there? – but sometimes they can be intentional, such as variables which are only used in release mode, or functions only called when logging is enabled.
I feel like this attribute is more useful to supress compiler warnings than to document your code for others, but at least we now have a standard way to do so.
[[fallthrough]] indicates that a fallthrough in a switch statement is intentional. Missing a
return in a switch case is a very common programmer error, so compilers usually warn about it, but sometimes a fallthrough can result in some very terse code.
Say we want to process an alert message. If it’s green, we do nothing; if it’s yellow, we record the alert; if it’s orange we record and trigger the alarm; if it’s red, we record, trigger the alarm and evacuate.
The most important function of
fallthrough is as documentation for maintainers. The presence of it in the code above shows anyone looking at the code that an orange alert is absolutely supposed to be recorded. Without the
fallthrough in the
Alert::Red case, it is not obvious whether a red alert is supposed to trigger the alarm and be recorded, or just evacuate everyone.
Functions declared with
[[nodiscard]] should not have their return values ignored by the caller. This can be useful if you want to ensure that callers check a return value, or that some scope guard object has a reasonable lifetime. Types can be marked
[[nodiscard]] to implicitly mark all functions returning that type as the same.
Those warnings will help the user notice that
do_something_else might be given a bad object, or the critical section won’t be locked.
Compilers have shipped non-standard extensions to express these concepts for years, but it’s great that we now have standard methods to do the same. Leave a comment if you have ideas for other attributes you would like to be added to the language!
Let me know what you think of this article on twitter @TartanLlama or leave a comment below!