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

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

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

Вместо

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

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

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

Кроме масштаба?

DeiDei 03.07.2019 11:01

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

deW1 03.07.2019 11:02

Я думаю, кто-то сказал несколько лет назад: «Я читал, что в C++ 11 мы можем создавать лямбда-операторы, подобные этому (...) Несмотря на то, что он короче, он влияет на читаемость кода (особенно для людей, которые не знают эта новая функция), что, я полагаю, является плохой практикой кодирования для разработки крупного программного обеспечения».

R2RT 03.07.2019 11:02

Я бы сказал, что он имеет точно такую ​​же длину, а не короче.

user7860670 03.07.2019 11:12

чистое мнение, следовательно, не ответ: if (int length = 2; length == 2) может быть удивительно, что вы видите это в первый раз, но в этом нет ничего сложного, что можно было бы понять, поэтому уже во второй раз это уже не будет большим сюрпризом и декларирование вещей в том объеме, в котором они принадлежат является одним из основных факторов, влияющих на читабельность. Имхо, ваше предположение неверно ;)

463035818_is_not_a_number 03.07.2019 11:15

Беспокойство о читаемости кода для людей, которые не знают языка, на котором написан код (что означает «не знаю эту новую функцию»), — это гонка на выживание.

user10762593 03.07.2019 22:10

Комментарий @another-dave R2RT был не только о людях, которые не знают эту функцию, это был просто акцент в скобках. Читабельность кода зависит не только от знания языка.

Barmar 03.07.2019 23:07

Они действительно должны довести это до логического завершения и позволить всем for, while, dowhile, if и switch иметь те же 3 части, что и текущий for. Первая часть определяет переменные, вторая часть — это фактическое условие (или значение для switch), последняя часть будет выполняться после тела оператора (если только break не используется для выхода из него или условие ложно). Просто для консистенции.

hyde 04.07.2019 00:34

Но while' — это просто средняя часть for. Если вы хотите больше, чем средняя часть, напишите for вместо while . Какой смысл делать их одинаковыми, кроме ключевого слова? (Кстати, я думаю, что «go» полностью избавляется от циклов while, исходя из этой предпосылки)

user10762593 04.07.2019 01:14

@another-dave согласился на гонку на выживание. Я не могу получить ?: через код-ревью... :(

Baldrickk 04.07.2019 18:07

Вы должны позволить мне сделать обзор вашего кода... Я часто предлагаю заменить операторы if-else одним безусловным оператором, содержащим условное выражение; это ИМО «легче читать», если более длинная форма содержит много повторяющегося текста. В любом случае, почти все «легче читаемые» позиции являются мнениями, а не эмпирическими фактами. Моя позиция: «будьте краткими, не путайтесь в коде».

user10762593 04.07.2019 20:04
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
81
11
10 152
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Is there any advantage of using this feature other than making the code shorter?

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

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

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

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

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

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

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

вы можете использовать if (auto p =get ()), так как оператор bool определен

sudo rm -rf slash 04.07.2019 08:18
Ответ принят как подходящий

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

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

Я возьму это последнее предложение и наклею его на двухметровый постер.

Quentin 04.07.2019 11:17

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

Galik 04.07.2019 12:37

Или со слабым указателем: if (auto p = ptr.lock(); p && p->foo()) bar(*p);

Deduplicator 04.07.2019 15:12

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

TLW 05.07.2019 03:46

Лучше задать вопрос «в чем преимущество этого перед {int i = 2; if (i == 2) {...}}» (обратите внимание на дополнительную область действия).

TLW 05.07.2019 03:47

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

Currently, the initializer is either declared before the statement and leaked into the ambient scope, or an explicit scope is used. With the new form, such code can be written more compactly, and the improved scope control makes some erstwhile error-prone constructions a bit more robust.

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

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

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

Не могли бы вы уточнить, что вы цитируете предложение? Особенно второй абзац. Я предлагаю блок-кавычки.

StoryTeller - Unslander Monica 03.07.2019 11:09

Спасибо @StoryTeller, да, я процитировал второй абзац из предложения open-std, включенного в C++17.

Abhishek Sinha 03.07.2019 11:12

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

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
}

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

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

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";
}

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

Я понимаю, что это субъективно, но я настоятельно предпочитаю вашу "грубую" версию той, где используется if-initializer. Мне так легче читать и понимать.

Fabio says Reinstate Monica 04.07.2019 12:15

@FabioTurati Я полагаю, это потому, что вы хорошо с ней знакомы, а другая версия новая. Но со временем я ожидаю, что if-initializer переиграет что-нибудь подобное.

Stack Danny 04.07.2019 19:08

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

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

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

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

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

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

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

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

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

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

Другие вопросы по теме