Не знаю, як інші програмісти, але я під час читання коду намагаюсь фокусуватись на даних, з якими цей код працює. Перша річ, яку треба зрозуміти при знайомстві з новим кодом — як конкретний тип даних використовується у конструкторах, деструкторах та інших засобах, що додають неявної функціональності.
Якщо частина коду працює зі змінними, що містять цілі числа, буде легко уявити, який саме асемблерний код буде згенеровано. Це ж саме стосується й чисел зі рухомою комою, і взагалі будь-яких інших простих типів даних. Коли ви починаєте використовувати особливості 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
будь-де у повсякденному програмуванні. А краще, взагалі не використовуйте.
Коментарі (1)