Делает ли auto сложным для понимания 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 - это нечто, что содержит индекс. Каков точный тип, совершенно не имеет значения для большинства случаев.
PlasmaHH

31
Так что не пиши auto x = GetX();, выбери лучшее имя, чем оно на xсамом деле говорит тебе, что оно делает в этом конкретном контексте ... это часто более полезно, чем его тип в любом случае.
Джонатан Уэйкли

11
Если использование большего числа типов делает программисту трудным чтение кода, либо код, либо программист нуждаются в серьезном улучшении.
CA Макканн

Ответы:


100

Краткий ответ: более полно, мое текущее мнение о 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будет продолжать преобразовываться в правильный тип. Если вместо этого вы фиксируете явный тип, изменение типа выражения приведет к внедрению тихих преобразований, когда новый тип преобразуется в старый тип, или ненужных разрывов сборки, когда новый тип все еще работает, как старый тип, но не преобразуется в старый. тип (например, когда вы меняете a mapна a 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. Хотя я бы не стал этого делать, если сейчас нет предупреждений, но я хочу получать предупреждения в будущем, если типы изменяются потенциально опасным образом.
Бьярке Хаммерсхольт Рун

6
Одна вещь, с которой я нахожу, autoсостоит в том, что мы должны стремиться программировать против интерфейсов (не в смысле ООП), а не против конкретных реализаций. Точно так же и с шаблонами. Вы жалуетесь на «трудно читаемый код», потому что у вас есть параметр типа шаблона, Tкоторый используется везде? Нет, я так не думаю. В шаблонах мы также создаем код для интерфейса, так как многие люди называют это уткой во время компиляции.
Xeo

6
«Используя авто-гарантии, вы получите правильный тип». Совсем не правда. Это только гарантирует, что вы получите тип, предписанный другой частью вашего кода. Правильно это или нет, совершенно неясно, когда вы прячете это позади auto.
Гонки легкости на орбите

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

что ПОЛУЧИЛА: herbutter.com/2013/08/12/… Я не вижу, как этот "сюрприз initializer_list" является сюрпризом; фигурные скобки вокруг =RHS не имеют особого смысла для любой другой интерпретации (штрих-скобочный список инициализации, но вам нужно знать, что вы инициализируете, что является оксюмороном auto). Тот , который является удивительным является auto i{1}также выводя initializer_list, несмотря подразумевающих не принимать это приготовилось Init-список , а принимать это выражение и использовать его тип ... но мы получаем initializer_listтам. К счастью, C ++ 17 исправляет все это.
underscore_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 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()) { ... }

против

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

В случаях, когда вы объявляете переменную, использование autoпозволяет типу оставаться невысказанным, как во многих выражениях. Вы, вероятно, должны попытаться решить для себя, когда это помогает удобочитаемости и когда это мешает.

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

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


21
+1 autoпозволяет создавать именованные переменные с неименованными или неинтересными типами. Значимые имена могут быть полезны.
Mankarse

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

27

ИМО, вы смотрите на это в значительной степени наоборот.

Дело не в том, чтобы autoприводить к коду, который не читается или еще менее читается. Речь идет о (в надежде, что) наличии явного типа возвращаемого значения, что компенсирует тот факт, что (по-видимому) неясно, какой тип будет возвращен какой-либо конкретной функцией.

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

Если здесь есть проблема, это не так auto. Это с остальной частью кода, и вполне вероятно, что явного типа достаточно, чтобы помочь вам увидеть и / или исправить основную проблему. Как только вы исправите эту реальную проблему, удобочитаемость кода auto, как правило, будет в порядке.

Честно говоря, я должен добавить: я имел дело с несколькими случаями, когда такие вещи были не столь очевидны, как вам хотелось бы, и решение проблемы также было довольно несостоятельным. Просто для одного примера, я несколько лет назад консультировал компанию, которая ранее объединилась с другой компанией. В итоге они получили кодовую базу, которая была «сплочена вместе», а не объединена. Составляющие программы начали использовать разные (но довольно похожие) библиотеки для аналогичных целей, и хотя они работали над тем, чтобы объединить вещи более чисто, они все же сделали это. В большинстве случаев единственным способом угадать, какой тип будет возвращен данной функцией, было узнать, откуда возникла эта функция.

Даже в таком случае вы можете помочь прояснить несколько вещей. В этом случае весь код начинался в глобальном пространстве имен. Простое перемещение значительного количества в некоторые пространства имен устраняет конфликты имен и значительно облегчает отслеживание типов.


17

Есть несколько причин, почему я не люблю auto для общего пользования:

  1. Вы можете рефакторинг кода без его изменения. Да, это одна из тех вещей, которые часто упоминаются как преимущество использования авто. Просто измените тип возврата функции, и если весь код, который ее вызывает, использует auto, никаких дополнительных усилий не требуется! Вы нажимаете кнопку compile, он создает - 0 предупреждений, 0 ошибок - и вы просто продолжаете и проверяете свой код без необходимости разбираться с беспорядком просмотра и потенциальным изменением 80 мест, где используется функция.

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

1a. Я верю в понятие «самодокументируемый код». Причиной самодокументируемого кода является то, что комментарии имеют тенденцию устаревать, больше не отражая то, что делает код, в то время как сам код - если написан явным образом - не требует пояснений, всегда остается актуальным на его намерение, и не оставит вас в замешательстве с несвежими комментариями. Если типы могут быть изменены без необходимости изменять сам код, то сам код / ​​переменные могут устареть. Например:

auto bThreadOK = CheckThreadHealth ();

За исключением проблемы, что CheckThreadHealth () в какой-то момент был подвергнут рефакторингу для возврата значения enum, указывающего состояние ошибки, если оно есть, вместо bool. Но человек, который сделал это изменение, пропустил проверку этой конкретной строки кода, и компилятор не помог, потому что он компилировался без предупреждений или ошибок.

  1. Возможно, вы никогда не узнаете, что такое настоящие типы. Это также часто указывается в качестве основного «преимущества» авто. Зачем изучать, что дает вам функция, когда вы можете просто сказать: «Кого это волнует? Она компилируется!»

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

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

  1. Ввод кода при его первоначальном написании не самая трудоемкая часть программирования. Да, auto делает написание кода быстрее на начальном этапе. Как заявление об отказе, я набираю> 100 WPM, так что, возможно, это не беспокоит меня так же, как другие. Но если бы все, что мне нужно было сделать, это написать новый код весь день, я был бы счастливым туристом. Самая трудоемкая часть программирования - это диагностика трудно воспроизводимых ошибок в крае, часто возникающих в результате неочевидных неявных проблем, таких как, например, чрезмерное использование auto (ссылка или копия, подписанный и неподписанный, float против int, bool против указателя и т. д.).

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

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

Еще одно полезное приложение auto, расширяющее возможности языка, - создание временных файлов в макросах, не зависящих от типа. Это то, что вы не могли сделать раньше, но вы можете сделать это сейчас.


4
Ты сделал это. Хотел бы я дать этому +2.
Учитель

Хороший "чертовски осторожный" - ответ. @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: вопрос в том, действительно ли сейчас важно, ЧТО именно «запись» точно? Я думаю, что более важно, ЧТО это запись, фактический базовый тип примитива - это еще один уровень абстракции. Таким образом, без auto, вероятно, будет:MyClass::RecordTy record = myObj.FindRecord (something)
paul23

2
@ paul23: Что выигрывает от использования auto по сравнению с типом, тогда, если ваше единственное возражение - «я не знаю, как это использовать». Либо заставляет вас искать это в любом случае.
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

Я весьма удивлен, что никто еще не указал, что auto помогает, если нет четкого типа. В этом случае вы либо решаете эту проблему, используя #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();

на самом деле рассказать что-нибудь еще о типе х? Он говорит, что это то, что возвращается оттуда, но это именно то, что авто. Это просто избыточно - «материал» здесь написан 3 раза - это, на мой взгляд, делает его менее читабельным, чем «автоматическая» версия.


5
Правильный способ обработки специфичных для платформы типов для typedefних.
Мастер

3

Читаемость субъективна; вам нужно посмотреть на ситуацию и решить, что лучше.

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

Кроме того, я бы добавил следующее: убедитесь, что вы смотрите на удобочитаемость, а не на удобство записи. Код, который легко написать, обычно нелегко читать, и наоборот. Например, если бы я писал, я бы предпочел авто. Если бы я читал, может быть, более длинные объявления.

Тогда есть последовательность; насколько это важно для вас? Желаете ли вы auto в одних частях и явные объявления в других, или один непротиворечивый метод?


2

Я возьму в качестве преимущества менее читаемый код и буду поощрять программиста использовать его все больше и больше. Почему? Ясно, что если код, использующий auto, трудно читать, то и его будет сложно писать. Программист вынужден использовать значимое имя переменной , чтобы улучшить свою работу.
Возможно, в начале программист может не написать значимые имена переменных. Но в конечном итоге, исправляя ошибки или просматривая код, когда он / она вынужден объяснять код другим, или в не столь скором будущем он / она объясняет код специалистам по техническому обслуживанию, программист осознает ошибку и будет использовать значимое имя переменной в будущем.


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

2

У меня есть два руководства:

  • Если тип переменной очевиден, утомительно писать или трудно определить, используйте auto.

    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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.