Инициализация переменных в операторе if - PullRequest
68 голосов
/ 03 июля 2019

Я читал, что в C ++ 17 мы можем инициализировать переменные в if инструкциях, подобных этому

if (int length = 2; length == 2)
    //execute something

Вместо

int length = 2;
if (length == 2)
    //do something

Несмотря на то, что он короче, он влияет на читаемость кода (особенно для людей, которые не знают эту новую функцию), что, как я полагаю, является плохой практикой кодирования для разработки больших программ.

Есть ли какое-либо преимущество использования этой функции, кроме сокращения кода?

Ответы [ 6 ]

88 голосов
/ 03 июля 2019

Ограничивает область действия length только if. Таким образом, вы получаете те же преимущества, которые мы получили изначально, когда нам было разрешено написать

for(int i = 0; i < ... ; ++i) {
   // ...
}

Вместо переменной утечки

int i;
for(i = 0; i < ... ; ++i) {
   // ...
}

Краткосрочные переменные лучше по нескольким причинам. Но назвать пару:

  1. Чем короче что-то живое, тем меньше нужно помнить при чтении несвязанных строк кода. Если i не существует вне цикла или оператора if, то нам не нужно обращать внимание на его значение вне их. Мы также не должны беспокоиться о том, что его значение будет взаимодействовать с другими частями программы, которые находятся за пределами запланированной области (что может произойти, если i выше будет повторно использован в другом цикле). Это облегчает понимание кода и его рассуждение.

  2. Если переменная содержит ресурс, то этот ресурс теперь удерживается в течение максимально короткого периода времени. И это без посторонних фигурных скобок. Также стало ясно, что ресурс относится только к if. Рассмотрим это как мотивирующий пример

    if(std::lock_guard _(mtx); guarded_thing.is_ready()) {
    }
    

Если ваши коллеги не знают об этой функции, научите их! Умиротворяющие программисты, которые не хотят учиться, являются плохим оправданием, чтобы избегать функций.

21 голосов
/ 03 июля 2019

Есть ли какое-либо преимущество использования этой функции, кроме сокращения кода?

Вы уменьшаете переменную область действия.Это имеет смысл и повышает удобочитаемость, поскольку усиливает локальность идентификаторов, о которых вам нужно рассуждать.Я согласен с тем, что следует избегать длинных операторов init внутри операторов if, но для коротких вещей это нормально.

Обратите внимание, что вы уже можете выполнить инициализацию и переход на результат в пре-C ++ 17:

int *get(); // returns nullptr under some condition

if (int *ptr = get())
    doStuff();

Это зависит от личного мнения, но вы можете считать явное условие более читабельным:

if (int *ptr = get(); ptr != nullptr)
    doStuff();

Кроме того, вы можете возразить против читабельности функции, ссылаясь на тот факт, чтолюди не привыкли, это опасно.Люди не привыкли к умным указателям в какой-то момент, но сегодня мы все согласны (я полагаю), что это хорошо, что они там.

16 голосов
/ 03 июля 2019

Новая форма оператора if имеет много применений.

В настоящее время инициализатор либо объявляется перед оператором и просачивается в окружающую среду, либо используется явная область.С новой формой такой код может быть написан более компактно, а улучшенное управление областью делает некоторые ранее подверженные ошибкам конструкции немного более устойчивыми.

Открыть стандартное предложение для оператора If с инициализатором

enter image description here

Итак, в целом, это утверждение упрощает общие шаблоны кода и помогает пользователям ограничивать области видимости.

Надеюсьэто помогает!

9 голосов
/ 03 июля 2019

В целях минимизации области видимости переменных существует идиома, которая определяет ресурс, только если он действителен при создании (например, объекты потока файлов ):

if(auto file = std::ifstream("filename"))
{
    // use file here
}
else
{
    // complain about errors here
}

// The identifier `file` does not pollute the wider scope

Иногда вы хотите иметь возможность изменить логику этого теста, чтобы сделать сбой основным предложением, а действительный ресурс - предложением else.Ранее это было невозможно.Но теперь мы можем сделать:

if(auto file = std::ifstream("filename"); !file)
{
    // complain about errors here
}
else
{
    // use file here
}

В качестве примера можно привести исключение:

if(auto file = std::ifstream(filename); !file)
    throw std::runtime_error(std::strerror(errno));
else
{
    // use file here
}

Некоторым людям нравится кодировать, чтобы функция прерывала работу раньше на ошибку и в противном случае прогресс.Эта идиома физически ставит логику прерывания выше логики продолжения, которую некоторые люди могут найти более естественной.

7 голосов
/ 03 июля 2019

Это особенно полезно для логических событий.Рассмотрим этот пример:

char op = '-';
if (op != '-' && op != '+' && op != '*' && op != '/') {
    std::cerr << "bad stuff\n";
}

Кажется немного грубым.Если вы не очень хорошо знакомы с OR, AND с отрицаниями, вам, возможно, придется остановиться и подумать об этой логике, которая обычно плохая.С помощью if-initialization вы можете добавить выразительность.

char op = '-';
if (bool op_valid = (op == '-') || (op == '+') || (op == '*') || (op == '/'); !op_valid) {
    std::cerr << "bad stuff\n";
} 

именованная переменная может быть повторно использована внутри if.Например:

if (double distance = std::sqrt(a * a + b * b); distance < 0.5){
    std::cerr << distance << " is too small\n";
}

Это замечательно, особенно если учесть, что переменная ограничена и, следовательно, не загрязняет пространство.

6 голосов
/ 04 июля 2019

Это расширение существующей функции, которая помогает читабельности в моем опыте.

if (auto* ptr = get_something()) {
}

Здесь мы оба создаем переменную ptr и проверяем, что она не равна нулю.Область действия ptr ограничена тем, где она действительна.Гораздо проще убедить себя в том, что любое использование ptr действительно.

Но что, если мы говорим о чем-то, что не преобразуется в bool таким образом?

if (auto itr = find(bob)) {
}

Это не работает.Но с помощью этой новой функции мы можем:

if (auto itr = find(bob); itr != end()) {
}

Добавить предложение, говорящее «когда эта инициализация действительна».

По сути, это дает нам набор токенов, которые означают «инициализировать некоторые»выражение, и когда он действителен, сделайте некоторый код. Если он недействителен, откажитесь от него. "

Было нелепо делать трюк с тестом указателя начиная с C ++ 98.Как только вы это охватите, это расширение будет естественным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...