Ініціалізація змінних у операторі “якщо”


80

Я читав, що в C ++ 17 ми можемо ініціалізувати змінні в ifтаких операторах

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

Замість

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

Незважаючи на те, що він коротший, він впливає на читабельність коду (особливо для людей, які не знають цієї нової функції), що, на мою думку, є поганою практикою кодування для розробки великого програмного забезпечення.

Чи є якась перевага використання цієї функції, крім скорочення коду?


38
Окрім розмаху?
DeiDei

10
Я думаю, хтось сказав кілька років тому "Я читав, що в C ++ 11 ми можемо створювати такі лямбда-висловлювання (...) Хоча він коротший, він впливає на читаність коду (особливо для людей, які не знають ця нова функція), що, на мою думку, є поганою практикою кодування для розробки великого програмного забезпечення ".
R2RT

9
Я б сказав, що він має точно однакову довжину, а не коротшу.
user7860670

5
чиста думка, отже, не відповідь: if (int length = 2; length == 2)можливо, дивно, що ти бачиш це вперше, але це нічого складного, що ніхто не міг зрозуміти, тому вже вдруге це вже не буде великим сюрпризом, і декларування матеріалів у тому обсязі, куди йому належить, є один з головних факторів, що сприяють читаності. Імхо, ваша передумова помилкова;)
greatest_prime_is_463035818

14
Турбота про читаність коду для людей, які не знають мови, якою написаний код (саме це означає «не знаю цієї нової функції») - це гонка до дна.

Відповіді:


97

Це обмежує сферу 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()) {
    }
    

Якщо ваші колеги не знають про цю функцію, навчіть їх! Задоволення програмістів, які не хочуть вчитися, є поганим приводом уникати функцій.


12
Я збираюся схопити це останнє речення і ляпнути його на двометровий плакат.
Квентін,

3
Крім того, короткочасні (жорсткомасштабні) змінні повинні зменшити кількість помилок, оскільки ви не зможете випадково повторно використати змінну в коді після того, як її призначення буде виконано.
Галик

1
Або зі слабким покажчиком:if (auto p = ptr.lock(); p && p->foo()) bar(*p);
Deduplicator

1
3. У більшості випадків компілятору дозволяється повторно використовувати простір стека. (Якщо ви коли-небудь
передаєте

Кращим запитанням може бути "яка перевага цього перед {int i = 2; if (i == 2) {...}}" (Зверніть увагу на додатковий обсяг.)
TLW

24

Чи є якась перевага використання цієї функції, крім скорочення коду?

Ви зменшуєте змінну область дії. Це має сенс і підвищує читабельність, оскільки посилює місцевість ідентифікаторів, про які вам потрібно міркувати. Я згоден з тим, що довгі ініціативні заяви всерединіif слід уникати операторів, але для коротких речей це нормально.

Зверніть увагу, що ви вже можете виконати ініціалізацію та розгалуження результату в pre-C ++ 17:

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

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

Це залежить від особистої думки, але ви можете вважати чіткий стан більш читабельним:

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

Окрім того, аргументувати читабельність функції, посилаючись на те, що люди до неї не звикли, небезпечно. Люди в якийсь момент не звикли до розумних покажчиків, але все-таки ми всі сьогодні погоджуємось (думаю), що добре, що вони там.


4
Ви могли б використовувати, if (auto p =get ())оскільки визначено оператор bool
sudo rm -rf коса риса

19

Нова форма оператора if має багато застосувань.

В даний час ініціалізатор або оголошується перед оператором і витікає в навколишнє середовище, або використовується явна область. З новою формою такий код можна писати більш компактно, а вдосконалений контроль області робить деякі колишні конструкції, схильні до помилок, трохи надійнішими.

Відкрийте стандартну пропозицію для оператора If з ініціалізатором

введіть тут опис зображення

Отже, підсумовуючи, це твердження спрощує загальноприйняті шаблони коду та допомагає користувачам не обмежувати обсяги.

Сподіваюся, це допоможе!


Не могли б ви дати зрозуміти, що цитуєте пропозицію? Особливо другий абзац. Я пропоную блок-котирування.
StoryTeller - Unslander Monica

Дякую @StoryTeller, так, я цитував другий абзац із пропозиції open-std, яка включена в C ++ 17.
Абхішек

10

З метою мінімізації обсягу змінних існує ідіома, яка визначає ресурс, лише якщо він дійсний при створенні (наприклад, об'єкти потоку файлів ):

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
}

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


8

Це особливо корисно для логічних подій. Розглянемо цей приклад:

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

Це чудово, особливо з огляду на те, що змінна має масштаб і тому не забруднює простір згодом.


2
Я усвідомлюю, що це суб’єктивно, але я віддаю перевагу вашій «грубій» версії перед версією з ініціалізатором if. Мені легше читати та розуміти.
Фабіо каже "

@FabioTurati Я думаю, це тому, що ви добре знайомі з нею, а інша версія нова. Але з часом я очікую, що ініціалізатор if переграє щось подібне.
Денні

7

Це продовження існуючої функції, яка допомагає читати, на мій досвід.

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

Тут ми обидва створюємо змінну ptrі перевіряємо, чи вона не є нульовою. Сфера застосування ptrобмежена тим, де це дійсно. Набагато простіше переконати себе в тому, що всяке вживання ptrє дійсним.

Але що, якщо ми говоримо про те, що не перетворюється на boolтакий шлях?

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

Це не працює. Але за допомогою цієї нової функції ми можемо:

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

Додайте речення "коли ця ініціалізація дійсна".

По суті, це дає нам набір лексем, які означають "ініціалізувати якийсь вираз, і коли він дійсний, ввести якийсь код. Коли він не дійсний, відкиньте його".

Починати фокус із тестуванням покажчика було ідіоматично ще з C ++ 98. Отримавши це, це продовження є природним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.