Чому я ненавиджу використання auto у C++

3 хв. читання

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

Якщо частина коду працює зі змінними, що містять цілі числа, буде легко уявити, який саме асемблерний код буде згенеровано. Це ж саме стосується й чисел зі рухомою комою, і взагалі будь-яких інших простих типів даних. Коли ви починаєте використовувати особливості C++, вам доводиться мати справу з неявними «сюрпризами» у вигляді конструкторів, деструкторів, неявних перетворень та перевантажених операторів.

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

auto results = SortByName( input );
 
for ( auto i = results.begin( ); i < results.end( ); ++i )
    // ...
 
StoreResults( results );

Скажіть, будь ласка, як працює цей цикл? Що робить оператор =? Чи відбувається неявне приведення типів після того, як ми передамо results до функції StoreResults? Що являє собою begin(), що таке та як в даному випадку поводитиметься оператор ++. На жодне з цих питань неможливо дати відповідь (принаймні, зважаючи на те, що я в цілому думаю про C++), оскільки код працює з повністю непрозорими даними. Яка тут є вигода від використання auto? На мій погляд, ніякої.

Глянемо на приклад без auto:

struct Results
{
    char** entries;
    int entryCount;
};
 
Results results = SortByName( input );
 
for ( int i = 0; i < results.entryCount; ++i )
{
    char* entry = results.entries[ i ];
    // ...
}
 
StoreResults( results );

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

Код з непотрібними абстракціями поганий тим, що доводиться витрачати більше часу, щоб зрозуміти, як він працює. При цьому додаткові витрати часу нічим не компенсуються, тому в підсумку отримаємо негативний ефект. У першому прикладі, щоб зрозуміти, який тип даних у results, доводиться обов'язково переглядати реалізацію SortByName, щоб дізнатись, який тип вона повертає.

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

Будь ласка, не використовуйте auto будь-де у повсякденному програмуванні. А краще, взагалі не використовуйте.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.6K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація