Похоже, что это auto
была довольно значительная особенность, которая должна быть добавлена в C ++ 11, которая, кажется, следует за многими новыми языками. Как и в языке, подобном Python, я не видел явного объявления переменных (я не уверен, возможно ли это с использованием стандартов Python).
Есть ли недостаток в использовании auto
для объявления переменных вместо их явного объявления?
c++
c++11
type-inference
auto
DxAlpha
источник
источник
Ответы:
Вы спрашивали только о недостатках, поэтому я выделю некоторые из них. При правильном использовании
auto
имеет несколько преимуществ. Недостатки связаны с простотой злоупотреблений и повышенным потенциалом поведения кода непреднамеренным образом.Основным недостатком является то, что при использовании
auto
вы не обязательно знаете тип создаваемого объекта. Есть также случаи, когда программист может ожидать, что компилятор выведет один тип, но компилятор непреклонно выведет другой.Учитывая объявление как
Вы не обязательно знаете, что это за тип
result
. Это могло бы бытьint
. Это может быть указатель. Это может быть что-то еще. Все они поддерживают разные операции. Вы также можете существенно изменить код с помощью незначительных изменений, таких какпотому что в зависимости от того, какие существуют перегрузки для
CallSomeFunction()
типа результата, он может быть совершенно другим - и последующий код может, следовательно, вести себя совершенно иначе, чем предполагалось. Вы могли бы внезапно вызвать сообщения об ошибках в более позднем коде (например, впоследствии пытаться разыменоватьint
, пытаться изменить то, что сейчасconst
). Более зловещее изменение - это когда ваше изменение проходит мимо компилятора, но последующий код ведет себя по-разному и неизвестно - возможно, с ошибками.Поэтому отсутствие точного знания типа некоторых переменных затрудняет строгое обоснование заявления о том, что код работает так, как задумано. Это означает, что необходимо приложить больше усилий для обоснования требований «пригодности для использования» в областях с высокой критичностью (например, критически важных для безопасности или критически важных).
Другой, более распространенный недостаток - это соблазн для программиста использовать его
auto
как тупой инструмент, чтобы заставить код компилироваться, вместо того, чтобы думать о том, что делает код, и работать над тем, чтобы сделать его правильным.источник
auto
, то большинство утилитарных языков страдают таким недостатком по дизайну!CallSomeFunction()
возвращает другой тип в зависимости от последовательности его аргументов, это является недостатком дизайнаCallSomeFunction()
, а не проблемойauto
. Если вы не читаете документацию по функции, которую используете, до ее использования, это проблема программиста, а не проблемаauto
. - Но я понимаю, что вы играете здесь адвоката дьявола, просто у Нира Фридмана гораздо лучше.T CallSomeFunction(T, int, int)
быть дефект дизайна? Очевидно, что он «возвращает другой тип в зависимости от последовательности своих аргументов».auto
вы не обязательно знаете тип создаваемого объекта». Можете ли вы объяснить, почему это проблемаauto
, а не проблема временных выражений подвыражения? Почемуauto result = foo();
плохо, аfoo().bar()
нет?Это
auto
принципиально не является недостатком , но на практике это кажется проблемой для некоторых. По сути, некоторые люди либо: а) относятсяauto
к типу спасителя и отключают свой мозг при его использовании, либо б) забывают, что этоauto
всегда приводит к типам значений. Это заставляет людей делать такие вещи:Ой, мы просто глубоко скопировали какой-то объект. Часто это ошибка или сбой производительности. Тогда вы можете качаться и другим способом:
Теперь вы получите свисающую ссылку. Эти проблемы не вызваны
auto
вообще, поэтому я не считаю их законными аргументами против этого. Но похоже, чтоauto
эти проблемы становятся более распространенными (из моего личного опыта) по причинам, которые я перечислил в начале.Я думаю, что со временем люди будут приспосабливаться и понимать разделение труда:
auto
выводит базовый тип, но вы все еще хотите подумать об эталонности и константности. Но это занимает немного времени.источник
std::vector
). Быть дорогостоящим для копирования - это свойство не класса, а отдельных объектов. Таким образом,method_that_returns_reference
может относиться к объекту класса, который имеет конструктор копирования, но какой объект оказывается довольно дорогим для копирования (и не может быть перемещен из).std::vector
? (Потому что это может, да, или потому что вы не управляете классом, но это не главное) Если копирование дорого (и не имеет ресурса, потому что оно копируемое), почему бы не использовать COW для объекта? Локальность данных уже уничтожена размером объекта.= delete
это перегрузка. Хотя в целом то, что вы говорите, является решением. Это тема, которую я изучил, если вам интересно: nirfriedman.com/2016/01/18/… .В других ответах упоминаются недостатки, такие как «вы на самом деле не знаете, какой тип переменной». Я бы сказал, что это во многом связано с соглашением о неаккуратном именовании в коде. Если ваши интерфейсы имеют четкие названия, вам не нужно беспокоиться о том, какой именно тип. Конечно,
auto result = callSomeFunction(a, b);
мало что тебе говорит. Ноauto valid = isValid(xmlFile, schema);
говорит вам достаточно, чтобы использовать,valid
не заботясь о том, что его точный тип. В конце концов,if (callSomeFunction(a, b))
вы просто не знаете тип. То же самое с любыми другими временными объектами подвыражения. Поэтому я не считаю это реальным недостаткомauto
.Я бы сказал, что его основным недостатком является то, что иногда точный тип возвращаемого значения не тот, с которым вы хотите работать. В действительности, иногда фактический тип возвращаемого значения отличается от «логического» возвращаемого типа в качестве детали реализации / оптимизации. Шаблоны выражений являются ярким примером. Допустим, у нас есть это:
Логически, мы ожидаем , что
SomeType
будетVector
, и мы определенно хотим , чтобы рассматривать его как таковой в нашем коде. Однако, возможно, что в целях оптимизации используемая нами библиотека алгебры реализует шаблоны выражений, и фактический тип возвращаемого значения такой:Теперь проблема заключается в том, что
MultExpression<Matrix, Vector>
, по всей вероятности, будет хранитьconst Matrix&
иconst Vector&
внутренне; он ожидает, что он преобразуется в aVector
до конца своего полного выражения. Если у нас есть этот код, все хорошо:Однако, если бы мы использовали
auto
здесь, мы могли бы попасть в беду:источник
auto
него очень мало недостатков, поэтому я поддерживаю эту силу. И другие примеры прокси и т. Д. Включают в себя различные «строители строк» и аналогичные объекты, найденные в DSL.auto
прежде, особенно с библиотекой Eigen. Это особенно сложно, потому что проблема часто не обнаруживается в отладочных сборках.auto
может также кусаться при использовании матричной библиотеки Armadillo , которая интенсивно использует шаблонное метапрограммирование для целей оптимизации. К счастью, разработчики добавили функцию .eval (), которую можно использовать, чтобы избежать проблем сauto
auto
как правило, без какой-либо проверки типа (а разбрызгиваниеauto
везде снимает безопасность типов так же, как и везде). Это не очень хорошее сравнение.Одним из недостатков является то, что иногда вы не можете объявить
const_iterator
сauto
. В этом примере кода, взятого из этого вопроса, вы получите обычный (неконстантный) итератор :источник
iterator
в любом случае, так как ваша карта неconst
. если вы хотите преобразовать его в aconst_iterator
, либо явно укажите тип переменной как обычно, либо извлеките метод, чтобы ваша карта была константной в контексте вашейfind
. (Я бы предпочел последнее. SRP.)auto city_it = static_cast<const auto&>(map).find("New York")
? или, с C ++ 17,auto city_if = std::as_const(map).find("New York")
.Это делает ваш код немного сложнее или утомительнее для чтения. Вообразите что-то подобное:
Теперь, чтобы выяснить тип вывода, вам нужно отследить сигнатуру
doSomethingWithData
функции.источник
auto it = vec.begin();
намного легче читать, чем,std::vector<std::wstring>::iterator it = vec.begin();
например.Как этот разработчик, я ненавижу
auto
. Вернее, я ненавижу, как люди злоупотребляютauto
.Я придерживаюсь (сильного) мнения, что
auto
он помогает вам писать общий код, а не сокращает набор текста .C ++ - это язык, цель которого - позволить вам написать надежный код, а не минимизировать время разработки.
Это довольно очевидно из многих возможностей C ++, но, к сожалению, некоторые из более новых, подобных
auto
этому, уменьшают типизацию, вводя людей в заблуждение, заставляя их думать, что им следует начать лениться при наборе текста.В предварительные
auto
дни, люди использовалиtypedef
s, который был большим , потому чтоtypedef
позволили дизайнеру библиотеки , чтобы помочь вам понять, что тип возвращаемого значения должен быть, так что их библиотека работает , как ожидалось. При использованииauto
вы забираете этот элемент управления у дизайнера класса и вместо этого просите компилятор выяснить, каким должен быть тип, что удаляет один из самых мощных инструментов C ++ из набора инструментов и рискует нарушить их код.Как правило, если вы используете
auto
, это должно быть потому, что ваш код работает для любого разумного типа , а не потому , что вам просто лень записывать тип, с которым он должен работать. Если вы используетеauto
в качестве инструмента для облегчения лени, то в конечном итоге вы начинаете вносить незначительные ошибки в вашу программу, обычно вызванные неявными преобразованиями, которых не было, потому что вы использовалиauto
.К сожалению, эти ошибки трудно проиллюстрировать в коротком примере здесь, потому что их краткость делает их менее убедительными, чем реальные примеры, которые появляются в пользовательском проекте - однако, они легко встречаются в коде с большим количеством шаблонов, который ожидает, что определенные неявные преобразования потребуют место.
Если вы хотите пример, есть один здесь . Небольшое замечание: прежде чем испытывать искушение прыгать и критиковать код: имейте в виду, что многие известные и зрелые библиотеки были разработаны для таких неявных преобразований, и они существуют потому, что решают проблемы, которые могут быть трудными, если не невозможными. решить иначе. Попробуйте найти лучшее решение, прежде чем критиковать их.
источник
which was great because typedef allowed the designer of the library to help you figure out what the return type should be, so that their library works as expected. When you use auto, you take away that control from the class's designer and instead ask the compiler to figure out what the type should be
Не очень хорошая причина ИМО. Современные IDE, например Visual Studio 2015, позволяют проверять тип переменной путем наведения курсораauto
. Это * точно * так же, какtypedef
тот.typename std::iterator_traits<It>::value_type
. (2) Все дело в том , что выведенный тип потребности не быть «точно так же» , как правильный тип предписанию предыдущего дизайнера кода; используяauto
, вы лишаете дизайнера возможности указать правильный тип.vector<bool>
ерунда" ... простите? Как вы думаете,bitset
это реализовано? Или вы считаете битовые контейнеры бессмысленными?auto
Сам по себе не имеет недостатков , и я рекомендую (осторожно) использовать его везде в новом коде. Это позволяет вашему коду постоянно проверять тип и избегать тихой нарезки. (ЕслиB
происходит от,A
и функция, возвращающаяA
внезапно, возвращаетB
, тогдаauto
ведет себя как ожидалось, чтобы сохранить свое возвращаемое значение)Хотя унаследованный код до C ++ 11 может опираться на неявные преобразования, вызванные использованием переменных с явным типом. Изменение явно типизированной переменной
auto
может изменить поведение кода , поэтому вам следует быть осторожным.источник
auto
есть недостатки как таковые (или, по крайней мере, многие так считают). Рассмотрим пример, приведенный во втором вопросе этой дискуссии с Саттером, Александреску и Мейерсом: если у вас естьauto x = foo(); if (x) { bar(); } else { baz(); }
иfoo()
возвращаетсяbool
- что произойдет, еслиfoo()
изменения вернут перечисление (три варианта вместо двух)?auto
Код будет продолжать работать, но привести к неожиданным результатам.bool
вместоauto
чего-либо что-либо в случае enum с незаданной областью? Я могу ошибаться (не могу проверить здесь), но я думаю, что единственное отличие состоит в том, что преобразование вbool
происходит при объявлении переменной, а не при оценке условия вif
. Еслиenum
область действия ограничена, то преобразование вbool
не должно происходить без явного уведомления.Ключевое слово
auto
просто выводит тип из возвращаемого значения. Следовательно, он не эквивалентен объекту Python, напримерПоскольку
auto
выводится во время компиляции, он не будет иметь никаких недостатков во время выполнения вообще.источник
type()
в Python. Он выводит тип, он не создает новую переменную этого типа.decltype
.auto
специально для назначения переменных.О чем никто не упомянул здесь до сих пор, но для себя стоит ответить, если вы спросите меня.
Так как (даже если все должны знать, что
C != C++
) код, написанный на C, может быть легко спроектирован для обеспечения базы для кода C ++ и, следовательно, может быть спроектирован без особых усилий для совместимости с C ++, это может быть требованием для разработки.Я знаю о некоторых правилах, в которых некоторые четко определенные конструкции
C
недопустимы,C++
и наоборот. Но это просто приведет к повреждению исполняемых файлов, и применяется известное предложение UB, которое чаще всего замечают странные циклы, приводящие к сбоям или чему-либо еще (или даже могут остаться незамеченными, но здесь это не имеет значения).Но
auto
в первый раз 1 это меняется!Представьте, что вы использовали ранее
auto
как спецификатор класса хранения и передали код. Это даже не обязательно (в зависимости от способа его использования) «сломаться»; это на самом деле может молча изменить поведение программы.Это то, что нужно иметь в виду.
+1 По крайней мере, в первый раз, когда я знаю.
источник
int
» в C, вы заслуживаете всего плохого, что вы получите от этого. И если вы не полагаетесь на это, использованиеauto
в качестве спецификатора класса хранения наряду с типом даст вам приятную ошибку компиляции в C ++ (что в данном случае хорошо).Одна из причин, по которой я могу придумать, заключается в том, что вы теряете возможность принуждать возвращаемый класс. Если ваша функция или метод вернули длинную 64-битную строку, и вы хотели получить только 32 беззнаковых целых, то вы теряете возможность контролировать это.
источник
Как я описал в этом ответе,
auto
иногда это может привести к неожиданным ситуациям, которые вы не собирались делать. Вы должны явно сказать,auto&
чтобы иметь ссылочный тип, в то время как простоauto
можете создать тип указателя. Это может привести к путанице, если опустить весь спецификатор, что приведет к копированию ссылки вместо фактической ссылки.источник
auto
делает, никогда не выводя ни ссылку, ниconst
тип. Дляauto
справки лучше использоватьauto&&
. (универсальная ссылка) Если тип не является дешевым для копирования или владеет ресурсом, то для начала тип не должен копироваться.Еще один раздражающий пример:
генерирует предупреждение (
comparison between signed and unsigned integer expressions [-Wsign-compare]
), потому чтоi
это int со знаком. Чтобы избежать этого, вам нужно написать, например,или, может быть, лучше:
источник
size
возвратsize_t
, вы должны иметь возможность иметьsize_t
подобный литерал0z
. Но вы можете объявить UDL для этого. (size_t operator""_z(...)
)unsigned
вполне вероятно, что он не будет достаточно большим, чтобы вместить все значения вstd::size_t
основных архитектурах, поэтому в маловероятном случае, когда кто-то будет иметь контейнер с абсурдно гигантским количеством элементов, использованиеunsigned
может вызвать бесконечный цикл в нижнем диапазоне индексов. Хотя это вряд ли является проблемой,std::size_t
следует использовать ее для получения чистого кода, который должным образом сигнализирует о намерениях. Я не уверен, что дажеunsigned long long
строго гарантировано достаточно, хотя на практике это должно быть одинаково.unsigned long long
гарантированно будет как минимум 64 бита, но в теорииsize_t
, я думаю, может быть больше, чем это. Конечно, если в вашем контейнере> 2 ^ 64 элементов, у вас могут возникнуть более серьезные проблемы ... ;-)Я думаю, что
auto
это хорошо, когда используется в локализованном контексте, где читатель легко и очевидно может вычесть его тип или хорошо документирован с комментарием своего типа или именем, которое выводит реальный тип. Те, кто не понимает, как это работает, могут воспринимать это неправильно, например, использовать его вместоtemplate
или подобное. Вот несколько хороших и плохих вариантов использования на мой взгляд.Хорошее использование
итераторы
Функциональные указатели
Плохое использование
Поток данных
Функция Подпись
Тривиальные Случаи
источник
int
, вы должны набрать еще один символ, если хотитеauto
. Это недопустимоint
так же легко увидеть здесь и печататьint
короче. Вот почему это тривиальный случай.Я удивлен, что никто не упомянул об этом, но предположим, что вы вычисляете факториал чего-то:
Этот код выведет это:
Это был определенно не ожидаемый результат. Это произошло потому, что
auto
выводил тип переменной факториал так, какint
будто он был назначен1
.источник