Инициализация переменных в операторе if - программирование

Инициализация переменных в операторе if

Я читал, что в С++ 17 мы можем инициализировать переменные в таких выражениях if

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

Вместо

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

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

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

4b9b3361

Ответ 1

Это ограничивает область 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()) {
    }
    

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

Ответ 2

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

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

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

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

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

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

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

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

Ответ 3

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

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

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

enter image description here

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

Я надеюсь, что это помогает!

Ответ 4

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

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
}

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

Ответ 5

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

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

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

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

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

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

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

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

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

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

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

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