Since C++17, it is possible to add an initialization to an if
or a switch
, and this possibility has been extended to
range-based for
loops in C++20.
The intended use case of this feature is to declare and initialize variables that can be used in the condition or the range but whose scope does
not extend beyond the body of the control-flow statement.
For instance, in this compliant code, the intent is to lock the mutex associated with the object obj
while manipulating this object
and unlock it immediately after. A lock object is, therefore, declared in the initialization of the condition.
if (std::scoped_lock lock(obj.getMutex()); obj.isVisible()) {
obj.draw();
}
However, the language’s syntax also allows simple expressions to be written in this place as well as using declarations since C++23. This leads to
code that is more complex to read for no real benefits. In some cases, it can hide nasty bugs. Let’s revisit the previous example:
if (std::scoped_lock (obj.getMutex()); obj.isVisible()) {
obj.draw();
}
This very similar-looking code does not declare a variable in the initialization part of the if
. Instead, it creates a temporary lock
object that is then immediately discarded. The mutex is unlocked before isVisible
or draw
are called.
Note: A classical for
loop presents the same flexibility for its initialization part (the first part of the loop). However, since the
initialization part is not optional, it is common practice to use it for simple expressions and not only variable declarations. So, this rule does not
apply to classical for
loops.