Чи робить автоматично код C ++ важче зрозуміти?


122

Я бачив конференцію Герба Саттера, де він заохочує всіх програмістів на C ++ використовувати auto.

Мені довелося прочитати код C # деякий час тому, де varшироко використовувався, і код було дуже важко зрозуміти - щоразу, коли varвикористовувався, я повинен був перевірити тип повернення правої сторони. Іноді не раз, тому що я забув тип змінної через деякий час!

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

Я також знаю, що простіше написати:

auto x = GetX();

Чому:

someWeirdTemplate<someOtherVeryLongNameType, ...>::someOtherLongType x = GetX();

Але це пишеться лише один раз, і GetX()тип повернення перевіряється багато разів, щоб зрозуміти, який тип xмає.

Це змусило мене замислитись - чи autoробить C ++ код складнішим для розуміння?


29
Вам справді потрібно щоразу перевіряти тип повернення ? Чому тип не зрозумілий з коду? autoчасто може ускладнювати читання, коли вони вже важко читати, тобто функції занадто довгі, неправильно названі змінні тощо. Що стосується коротких функцій із гідно названими змінними, знаючи, що типи повинні бути одним з легких або №2 не мають значення.
Р. Мартіньо Фернандес

25
"Мистецтво" використання autoбагато в чому визначає, коли використовувати typedef. Ви самі визначаєте, коли це заважає і коли це допомагає.
ahenderson

18
Я думав, що у мене така ж проблема, але потім зрозумів, що я можу просто зрозуміти код, не знаючи типів. наприклад: "auto idx = get_index ();" тому idx - це щось, що містить індекс. Який точний тип, для більшості випадків є зовсім не важливим.
ПлазмаHH

31
Тому не пишіть auto x = GetX();, вибирайте краще ім'я, ніж xте, що насправді говорить вам про те, що він робить у конкретному контексті ... це часто корисніше, ніж його тип.
Джонатан Вейклі

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

Відповіді:


99

Коротка відповідь: Більш повно, моя поточна думка щодо того auto, що ви повинні використовувати autoза замовчуванням, якщо явно не хочете конверсії. (Трохи точніше, "... якщо ви не хочете явно привласнити тип, що майже завжди відбувається тому, що ви хочете конвертувати.")

Більш довга відповідь та обгрунтування:

Пишіть явний тип (а не auto) лише тоді, коли ви дійсно хочете явно взяти на себе зобов’язання з типом, що майже завжди означає, що ви хочете явно отримати конверсію до цього типу. Я згадую два основні випадки:

  • (Загальне) initializer_listСюрприз, який auto x = { 1 };виводить initializer_list. Якщо ви не хочете initializer_list, скажіть тип - тобто явно попросіть конверсію.
  • (Рідкісний) Випадок шаблонів виразів, наприклад, що auto x = matrix1 * matrix 2 + matrix3;фіксує помічник або тип проксі, який не повинен бути видимим програмісту. У багатьох випадках захоплювати цей тип добре і доброякісно, ​​але іноді, якщо ви дійсно хочете, щоб він звалився і зробив обчислення, тоді скажіть тип - тобто знову явно просите перетворення.

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

  • Правильність: Використовуючи autoгарантії, ви отримаєте правильний тип. Як висловлюється, якщо ви повторите себе (скажіть тип надмірно), ви можете і будете брехати (помиліться). Ось звичайний приклад: void f( const vector<int>& v ) { for( /*…*- У цей момент, якщо ви явно пишете тип ітератора, ви хочете пам’ятати про те, щоб написати const_iterator(чи не так?), Тоді як це autoпросто правильно.
  • Ремонтопридатність та надійність: Використання autoробить ваш код більш надійним на тлі змін, оскільки, коли тип виразу зміниться, autoвін продовжуватиме відповідати правильному типу. Якщо ви замість цього скористаєтеся явним типом, зміна типу виразу буде вводити тихі перетворення, коли новий тип переходить у старий тип, або непотрібні розриви збірки, коли новий тип все ще працює як старий тип, але не перетворюється на старий введіть (наприклад, коли ви змінюєте mapна unordered_map, і це завжди добре, якщо ви не покладаєтесь на замовлення, використовуючи autoдля своїх ітераторів ви безперешкодно переходите map<>::iteratorна unordered_map<>::iterator, але використовуючиmap<>::iterator скрізь явно означає, що ви витрачаєте свій цінний час на пульсацію механічного коду виправлення, якщо тільки не проходить стажист, і ви не зможете скористатися нудною роботою над ними).
  • Продуктивність: Оскільки autoгарантій, що неявна конверсія не відбудеться, вона гарантує кращу ефективність за замовчуванням. Якщо замість цього ви говорите тип, і він вимагає конверсії, ви часто мовчки отримуєте конверсію, очікували ви її чи ні.
  • Практичність: Використання auto- ваш єдиний хороший варіант для важкозаписаних та нездійснюваних типів, таких як лямбдати та помічники шаблонів, але не вдаючись до повторюваних decltypeвиразів або менш ефективних непрямих на зразок std::function.
  • Зручність: І, так, autoменше друкувати. Я згадую це останнє для повноти, тому що це загальна причина сподобатися, але це не найбільша причина його використання.

Отже: Віддавайте перевагу autoза замовчуванням. Він пропонує стільки простоти, продуктивності та чіткості, що ви тільки шкодите собі (і майбутнім обслуговувачам свого коду), якщо цього не зробите. Призначати явний тип лише тоді, коли ви це дійсно маєте на увазі, що майже завжди означає, що ви хочете явного перетворення.

Так, є (зараз) GotW з цього приводу.


14
Я вважаю авто корисним навіть тоді, коли мені хочеться конверсії. Це дозволяє мені явно попросити перетворення без повторення типу: auto x = static_cast<X>(y). static_castСтає ясно , що перетворення з метою і це дозволяє уникнути попереджень компілятора про перетворення. Зазвичай уникати попереджень компілятора не так добре, але я в порядку, не отримуючи попередження про конверсію, яке я ретельно розглядав, коли писав static_cast. Хоча я б не робив цього, якщо зараз немає попереджень, але я хочу отримати попередження в майбутньому, якщо типи змінюються потенційно небезпечним способом.
Bjarke Hammersholt Roune

6
Я вважаю auto, що ми повинні прагнути програмувати на інтерфейси (не в сенсі OOP), а не на конкретні реалізації. Так само і з шаблонами. Ви скаржилися на "важко читається код", оскільки у вас є параметр типу шаблону, Tякий використовується скрізь? Ні, я не думаю. У шаблонах ми також кодуємо інтерфейс, так як багато хто називає це час компіляції качок.
Ксео

6
"Використовуючи автоматичні гарантії, ви отримаєте потрібний тип." Не зовсім правда. Це лише гарантує, що ви отримаєте тип, передбачений якоюсь іншою частиною коду. Чи правильно це чи ні, зовсім незрозуміло, коли ви ховаєте це позаду auto.
Гонки легкості на орбіті

Я дуже здивований, що ніхто не піклується про IDE ... Навіть сучасні IDE неправильно підтримують перехід до визначення класу / структури у випадку autoзмінної, але майже всі вони роблять це правильно з явною специфікацією типу. Ніхто не використовує IDE? Усі використовують лише змінні int / float / bool? Усі вважають за краще зовнішню документацію для бібліотек, а не заголовки, що самодокументовані?
автомат

що GotW: herbsutter.com/2013/08/12 / ... Я не розумію , як це «initializer_list сюрприз» сюрприз; дужки навколо =RHS не мають особливого сенсу в будь-якій іншій інтерпретації (смужка, закреслена init-list, але вам потрібно знати, що ви ініціалізуєте, що таке оксиморон auto). Той , який є дивним є auto i{1}також виводячи initializer_list, незважаючи на увазі не приймати це приготувалося Init-список , а приймати цей вислів і використовувати його тип ... але ми отримуємо initializer_listтам. На щастя, C ++ 17 добре це виправляє.
підкреслюй_d

112

Це ситуація в кожному конкретному випадку.

Іноді код робить важче зрозуміти, іноді ні. Візьмемо, наприклад:

void foo(const std::map<int, std::string>& x)
{
   for ( auto it = x.begin() ; it != x.end() ; it++ )
   { 
       //....
   }
}

це, безумовно, легко зрозуміти і, безумовно, простіше написати, ніж власне декларація ітератора.

Я вже деякий час використовую C ++, але можу гарантувати, що я отримаю помилку компілятора при першому знімку в цьому, тому що забуду про те, const_iteratorі спочатку піде на iterator... :)

Я б використовував його для таких випадків, але не там, де він фактично обтяжує тип (як ваша ситуація), але це суто суб'єктивно.


45
Саме так. Кого, чорт, хвилює тип. Це ітератор. Мене не хвилює тип, все, що мені потрібно знати, - це я можу використовувати його для ітерації.
Р. Мартіньо Фернандес

5
+1. Навіть якби ви назвали тип, ви б назвали його таким std::map<int, std::string>::const_iterator, тож це не так, якби ім’я все одно багато розповідає про тип.
Стів Джессоп

4
@SteveJessop: Він принаймні говорить мені про дві речі: ключ є int, а значення - std::string. :)
Наваз

16
@Nawaz: і до цього не можна призначати, it->secondоскільки це ітератор const. Все , яка інформація є повторенням того , що знаходиться в попередньому рядку, const std::map<int, std::string>& x. Говорячи речі кілька разів, інколи краще повідомляйте, але це не загальне правило :-)
Стів Джессоп

11
TBH Я вважаю за краще for (anX : x)зробити це ще більш очевидним, що ми просто перебираємо x. Нормальний випадок, коли вам потрібен ітератор, коли ви змінюєте контейнер, але xцеconst&
MSalters

94

Подивіться на це по-іншому. Ви пишете:

std::cout << (foo() + bar()) << "\n";

або:

// it is important to know the types of these values
int f = foo();
size_t b = bar();
size_t total = f + b;

std::cout << total << "\n";

Іноді це не допомагає чітко виписати тип.

Рішення про те, чи потрібно згадати тип, не те саме, що рішення про те, чи потрібно розділити код на кілька операторів, визначивши проміжні змінні. У C ++ 03 обидва були пов’язані між собою, ви можете розглянути autoяк спосіб їх розділення.

Іноді надання явних типів може бути корисним:

// seems legit    
if (foo() < bar()) { ... }

vs.

// ah, there's something tricky going on here, a mixed comparison
if ((unsigned int)foo() < bar()) { ... }

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

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

Зокрема, при написанні загального коду є випадки, коли фактичний тип змінної не повинен мати важливого значення, але важливо, щоб він відповідав необхідному інтерфейсу. Так autoзабезпечується рівень абстракції, де ви ігноруєте тип (але, звичайно, компілятор цього не знає). Робота на відповідному рівні абстракції може досить багато допомогти читати, робота на "неправильному" рівні робить читання коду слоганом.


21
+1 autoдозволяє створювати названі змінні з неназваними або нецікавими типами. Значущі імена можуть бути корисними.
Манкарсе

Змішування підписане та ненаписане, якщо ви використовуєте ненаписане для правильного використання: модульна арифметика. Це не так, якщо ви неправомірно використовуєте підпис для додатного цілого числа. Практично жодна програма не використовує непідписані, але основна мова змушує її нерівномірно визначити sizeofяк неподписаний на вас.
curiousguy

27

ІМО, ви дивитесь на це дуже навпаки.

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

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

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

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

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


17

Є кілька причин, чому мені не подобається автоматичне використання для загального користування:

  1. Ви можете рефакторний код, не змінюючи його. Так, це одна з речей, які часто перераховуються як переваги використання авто. Просто змініть тип повернення функції, і якщо весь код, який викликає її, використовує автоматичне, додаткові зусилля не потрібно! Ви натискаєте компіляцію, вона створює - 0 попереджень, 0 помилок - і ви просто продовжуєте перевіряти свій код, не маючи справу з безладом перегляду та потенційним зміненням 80 місць використання функції.

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

1а. Я вірую в поняття «код, що самодокументує». Обґрунтуванням коду самодокументування є те, що коментарі, як правило, застарівають, більше не відображаючи, що робить код, тоді як сам код - якщо він написаний явно - є зрозумілим, завжди залишається актуальним з його наміром, і не залишить вас плутати з несвіжими коментарями. Якщо типи можна змінити без необхідності змінювати сам код, тоді код / ​​змінні можуть стати несвіжими. Наприклад:

auto bThreadOK = CheckThreadHealth ();

За винятком проблеми, що CheckThreadHealth () в якийсь момент був відновлений, щоб повернути значення перерахунку, що вказує на стан помилки, якщо такий є, замість bool. Але особа, яка внесла ці зміни, пропустила перевірку цього конкретного рядка коду, і компілятор не допоміг, оскільки він склав без попереджень і помилок.

  1. Ви ніколи не знаєте, що таке фактичні типи. Це також часто вказано як основну "перевагу" авто. Навіщо вчитися, яку функцію дає тобі, коли ти можеш просто сказати: "Кому все одно?

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

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

  1. Введення коду при первинному написанні не є найбільш трудомісткою частиною програмування. Так, автоматично спочатку записується якийсь код. Як відмова, я набираю> 100 WPM, тому, можливо, це мене не так сильно, як інші. Але якби я весь день писав новий код, я був би щасливим відпочивачем. Найбільш трудомісткою частиною програмування є діагностування важко відтворюваних, кращих помилок у коді, які часто є наслідком тонких не очевидних проблем - таких, як вигляд надмірного використання авто (можливо, буде введено посилання на копію, підписано проти неподписаного, float vs. int, bool vs. pointer тощо).

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

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

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


4
Ти впорався. Бажаю, щоб я міг дати це +2.
cmaster

Хороший "проклятий обережний" -відповідь. @cmaster: Ось це.
Дедуплікатор

Я знайшов ще один корисний випадок: auto something = std::make_shared<TypeWithLongName<SomeParam>>(a,b,c);. :-)
Notinlist

14

Так, це полегшує знання типу змінної, якщо ви її не використовуєте auto. Питання: чи потрібно знати тип вашої змінної, щоб прочитати код? Іноді відповідь буде так, іноді - ні. Наприклад, коли ви отримуєте ітератор від a std::vector<int>, чи потрібно вам знати, що це std::vector<int>::iteratorчи auto iterator = ...;достатньо? Все, що хто-небудь хотів би зробити з ітератором, пояснюється тим, що це ітератор - просто не має значення, який саме тип є.

Використовуйте autoв тих ситуаціях, коли ваш код не ускладнює читання.


12

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

Приклад 1

std::map <KeyClass, ValueClass> m;
// ...
auto I = m.find (something); // OK, find returns an iterator, everyone knows that

Приклад 2

MyClass myObj;
auto ret = myObj.FindRecord (something)// NOT OK, everyone needs to go and check what FindRecord returns

5
Це наочний приклад поганого іменування, що шкодить читабельності, а не справжній автоматичний. Ніхто не має найменшого уявлення про те, що робить "DoSomethingWeird", тому використання авто чи ні не зробить його більш читабельним. Документи вам доведеться перевірити в будь-якому випадку.
Р. Мартіньо Фернандес

4
Гаразд, зараз трохи краще. Я все ще знаходжу змінну погано названою, хоча це все ще шкодить. Якби ви писали, auto record = myObj.FindRecord(something)було б зрозуміло, що тип змінної був записом. Якщо назвати його itчи подібне, це стане зрозумілим, що він повертає ітератор. Зауважте, що навіть якщо ви не використовували auto, правильне іменування змінної означало б, що вам не потрібно повертатися до декларації, щоб переглянути тип з будь-якої точки функції . Я усунув свою незаконність, тому що приклад зараз не є повним сломанцем, але я все одно не купую аргументи тут.
Р. Мартіньо Фернандес

2
Додамо до @ R.MartinhoFernandes: питання полягає в тому, чи справді зараз важливо, ЩО саме "запис"? Думаю, важливіше, що це запис, власне основний примітивний тип - це інший шар абстракції. Отже, без авто, мабуть, було б:MyClass::RecordTy record = myObj.FindRecord (something)
paul23

2
@ paul23: Що з використанням автоматичного проти типу ви отримуєте, тоді, якщо ваше єдине заперечення - "я не знаю, як це використати". Або змушує вас шукати це все одно.
GManNickG

3
@GManNickG це говорить мені про точний тип незначущості.
paul23

10

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

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

for( std::map<std::pair<Foo,Bar>, std::pair<Baz, Bot>, std::less<BazBot>>::const_iterator it = things_.begin(); it != things_.end(); ++it )

.. або ...

for( auto it = things_.begin(); it != things_.end(); ++it )

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


4
+1 Ха-ха, всі представляють std::mapприклади, додатково зі складними аргументами шаблонів.
Наваз

1
@Nawaz: Легко придумати назви шаблонів із довгими шаблонами за допомогою maps. :)
Джон Дайблінг

@Nawaz: але мені цікаво, чому тоді ніхто не приходить з діапазоном, що базується на циклі, як краща і читабельніша альтернатива ...
PlasmaHH

1
@PlasmaHH, не всі петлі з ітераторами можна замінити на основі діапазону, forнаприклад, якщо ітератори недійсні в тілі циклу, і тому їх потрібно попередньо збільшувати або не збільшувати взагалі.
Джонатан Вейклі

@PlasmaHH: У моєму випадку MSVC10 не робить діапазон для циклів. Оскільки MSVC10 - це мій тестовий блок C ++ 11, я не маю великого досвіду роботи з ними.
Джон Дайблінг

8

Поки що багато хороших відповідей, але для того, щоб зосередитись на оригінальному питанні, я думаю, що Герб занадто далеко йде в своїх порадах, щоб використовувати їх autoвільно. Ваш приклад - це один випадок, коли використання autoочевидно шкодить читабельності. Деякі люди наполягають, що це не проблема із сучасними IDE, де ви можете навести курсор на змінну і побачити тип, але я не згоден: навіть людям, які завжди використовують IDE, іноді потрібно дивитись фрагменти коду поодиноко (подумайте про огляди коду , наприклад) і IDE не допоможе.

Підсумок: використовувати, autoколи це допомагає: тобто ітератори для циклів. Не використовуйте його, коли він змушує читача боротися з тим, щоб дізнатися його тип.


6

Я дуже здивований, що ще ніхто не зазначив, що авто допомагає, якщо немає чіткого типу. У цьому випадку ви або вирішуєте цю проблему, використовуючи #define або typedef в шаблоні, щоб знайти фактично корисний тип (а це іноді не тривіально), або просто використовуєте auto.

Припустимо, у вас є функція, яка повертає щось із певним типом:

#ifdef PLATFROM1
__int256 getStuff();
#else //PLATFORM2
__int128 getStuff();
#endif

Ви б віддали перевагу використанню відьом?

#ifdef PLATFORM1
__int256 stuff = getStuff();
#else
__int128 stuff = getStuff();
#endif

або просто просто

auto stuff = getStuff();

Звичайно, можна писати

#define StuffType (...)

також десь, але робить

StuffType stuff = getStuff();

насправді розповісти щось більше про тип x? Це говорить, що це те, що повертається звідти, але це саме те, що є авто. Це просто зайве - тут написано "речі" 3 рази - це, на мій погляд, робить його менш читабельним, ніж версія "авто".


5
Правильний спосіб обробки конкретних типів платформи - це саме typedefвони.
cmaster

3

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

Як ви зазначали, без автоматичних тривалих декларацій можуть виникнути безлад. Але, як ви також вказали, короткі декларації можуть видалити інформацію про тип, яка може бути цінною.

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

Потім є послідовність; наскільки це важливо для вас? Чи хочете ви авто в деяких частинах і чіткі декларації в інших, або один послідовний метод на всьому протязі?


2

Я візьму пункт менш читабельного коду як перевагу і закликаю програміста використовувати його все більше і більше. Чому? Зрозуміло, що якщо код, що використовує функцію auto, важко читати, тоді також буде важко написати. Програміст змушений використовувати змістовне ім'я змінної , щоб покращити свою роботу.
Можливо, на початку програміст може не записати змістовні імена змінних. Але врешті-решт, виправляючи помилки або переглядаючи код, коли йому доведеться пояснювати код іншим чи не в найближчому майбутньому, він / вона пояснює код людям, які обслуговують, програміст зрозуміє помилку і використає змістовне ім'я змінної в майбутньому.


2
У кращому випадку ви отримаєте людей, які пишуть імена змінних, як, myComplexDerivedTypeщоб доповнити відсутній тип, який захаращує код за типом повторення (скрізь, де використовується змінна), і який спонукає людей опустити призначення змінної у своєму імені . Мій досвід полягає в тому, що немає нічого такого непродуктивного, як активно ставити перешкоди в коді.
cmaster

2

У мене є два вказівки:

  • Якщо тип змінної очевидний, нудно писати або важко визначити, використовувати авто.

    auto range = 10.0f; // Obvious
    
    for (auto i = collection.cbegin(); i != cbegin(); ++i) // Tedious if collection type
    // is really long
    
    template <typename T> ... T t; auto result = t.get(); // Hard to determine as get()
    // might return various stuff
    
  • Якщо вам потрібна конкретна конверсія або тип результату не очевидний і може викликати плутанину.

    class B : A {}; A* foo = new B(); // 'Convert'
    
    class Factory { public: int foo(); float bar(); }; int f = foo(); // Not obvious
    

0

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

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

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