C++17 new feature - restrict variable scope to if and switch areas

Introduction

It is a very good coding style to limit the life cycle of variables to the specified area as much as possible. Sometimes we need to obtain a certain value when certain conditions are met, and then operate on this value.
In order to make this process easier, C++17 is equipped with initialization areas for if and switch.

In this case, we use the initialization statement to understand how to use it:
if: Suppose we want to find a letter in an alphabet, our std::map Member find completes this operation:

if (auto itr (character_map.find(c)); itr != character_map.end()) {
// *itr is valid. Do something with it.
} else {
// itr is the end-iterator. Don't dereference.
}
// itr is not available here at all

switch: This example looks like the letters entered by the player determine an in-game behavior. Find the operation corresponding to a letter by using switch:

switch (char c (getchar()); c) { case 'a': move_left(); break; case 's': move_back(); break; case 'w': move_fwd(); break; case 'd': move_right(); break; case 'q': quit_game(); break;
case '0'...'9': select_tool('0' - c); break; default:
std::cout << "invalid input: " << c << '\n';
}

Workflow

If and switch with initialization are equivalent to syntactic sugar.

if: before C++17

// if: before C++17
{
auto var(init_value); if (condition){
// branch A. var is accessible
} else {
// branch B. var is accessible
}
// var is still accessible
}

if: since C++17

// if: since C++17
if (auto var (init_value); condition){
// branch A. var is accessible
} else {
// branch B. var is accessible
}
// var is not accessible any longer

switch: before C++17

// switch: before C++17
{
auto var (init_value); switch (var) {
case 1: ...
case 2: ...
...
}
// var is still accessible
}

switch: since C++17

// switch: since C++17
switch(auto var (init_value); var){ case 1: ...
case 2: ...
...
}
// var is not accessible any longer

These useful features ensure code simplicity. Prior to C++17, code could only be surrounded by external parentheses, as shown in the example above. Shortening the life cycle of variables can help us keep the code clean and easier to refactor.

syntax extension

Another interesting example is critical section limiting variable lifetime. Let’s look at an example first:

if (std::lock_guard<std::mutex> lg {my_mutex}; some_condition) {
// Do something
}

First, create a std::lock_guard. This class receives a mutex as arguments to its constructor. This class locks the mutex in its constructor and then unlocks the mutex in its destructor when the code has finished running this area. This approach avoids errors caused by forgetting to unlock the mutex. Prior to C++17, an additional pair of parentheses was required to determine the scope of the unlock.
Another example of area restriction for weak pointers:

if (auto shared_pointer (weak_pointer.lock()); shared_pointer != nullptr) {
// Yes, the shared object does still exist
} else {
// shared_pointer var is accessible, but a null pointer
}
// shared_pointer is not accessible any longer

This example has a temporary shared_pointer variable that does "leak" into the current scope, although an if conditional block or outer parentheses will keep it in a useless state.
The if initialization section is useful when you want to use the output parameters of the traditional API:

if (DWORD exit_code; GetExitCodeProcess(process_handle, &exit_code)) { std::cout << "Exit code of process was: " << exit_code << '\n';
}
// No useless exit_code variable outside the if-conditional

The GetExitCodeProcess function is a kernel API function of the Windows operating system. It uses the return code to determine whether the given process has completed legal processing. When leaving the conditional domain, the variable is useless and the variable can be destroyed.
If code blocks with initialization sections are particularly useful in many situations, especially when initializing with output parameters of traditional APIs.
Note:
Using if and switch with initialization section can ensure the compactness of the code. This makes your code compact, easier to read, and easier to change during refactoring.

Guess you like

Origin blog.csdn.net/EBDSoftware/article/details/128482674