Я понимаю, почему auto
тип в C ++ 11 улучшает правильность и удобство обслуживания. Я читал, что это также может улучшить производительность ( почти всегда авто от Херба Саттера), но я упускаю хорошее объяснение.
- Как можно
auto
улучшить производительность? - Кто-нибудь может привести пример?
c++
performance
c++11
auto
DaBrain
источник
источник
Ответы:
auto
может помочь производительности, избегая неявных неявных преобразований . Пример, который я считаю убедительным, следующий.Видишь ошибку? Здесь мы думаем, что элегантно берем каждый элемент на карте с помощью константной ссылки и используем новое выражение диапазона для того, чтобы прояснить наше намерение, но на самом деле мы копируем каждый элемент. Это происходит потому , что
std::map<Key, Val>::value_type
этоstd::pair<const Key, Val>
неstd::pair<Key, Val>
. Таким образом, когда мы (неявно) имеем:Вместо того, чтобы брать ссылку на существующий объект и оставлять его при этом, мы должны выполнить преобразование типа. Вам разрешено принимать константную ссылку на объект (или временный) другого типа при условии, что доступно неявное преобразование, например:
Преобразование типов является допустимым неявным преобразованием по той же причине, по которой вы можете преобразовать a
const Key
в aKey
, но мы должны создать временный объект нового типа, чтобы учесть это. Таким образом, наш цикл эффективно:(Конечно, на самом деле нет
__tmp
объекта, он есть просто для иллюстрации, на самом деле неназванный временный объект просто обязанitem
для своей жизни).Просто меняется на:
просто сэкономил нам кучу копий - теперь ссылочный тип соответствует типу инициализатора, поэтому временное преобразование или преобразование не требуется, мы можем просто сделать прямую ссылку.
источник
std::pair<const Key, Val> const &
какstd::pair<Key, Val> const &
? Новичок в C ++ 11, не уверен, как диапазон иauto
играет в этом.auto
это повышение производительности. Поэтому я напишу это своими словами ниже.auto
улучшает производительность». Это просто пример, который «auto
помогает предотвратить ошибки программистов, которые снижают производительность». Я утверждаю, что между ними есть тонкое, но важное различие. Тем не менее +1.Поскольку
auto
выводит тип инициализирующего выражения, преобразование типов не выполняется. В сочетании с шаблонными алгоритмами это означает, что вы можете получить более прямые вычисления, чем если бы вы сами составляли тип - особенно когда вы имеете дело с выражениями, тип которых вы не можете назвать!Типичный пример взят из (ab) с использованием
std::function
:С помощью
cmp2
иcmp3
, весь алгоритм может встроить вызов сравнения, тогда как если вы создаетеstd::function
объект, вызов не только не может быть встроенным, но вы также должны пройти полиморфный поиск в стертой внутренней стороне оболочки функции.Еще один вариант на эту тему, что вы можете сказать:
Это всегда ссылка, привязанная к значению выражения вызова функции, и никогда не создающая никаких дополнительных объектов. Если вы не знаете тип возвращаемого значения, вы можете быть вынуждены создать новый объект (возможно, как временный) с помощью чего-то подобного
T && f = MakeAThing()
. (Более того,auto &&
даже работает, когда возвращаемый тип не является подвижным, а возвращаемое значение является prvalue)источник
auto
. Ваш другой вариант - «избегать случайных копий», но требует приукрашивания; почемуauto
вы просто набираете шрифт? (Я думаю, что ответ «вы ошиблись в типе, и он молча преобразуется»). Что делает этот пример менее понятным примером ответа Барри, нет? То есть, есть два основных случая: автоматический, чтобы избежать стирания типа, и автоматический, чтобы избежать ошибок тихого типа, которые случайно конвертируются, оба из которых имеют стоимость времени выполнения.std::bind
,std::function
иstd::stable_partition
все были встроены? Или просто, что на практике ни один компилятор C ++ не будет достаточно агрессивно встроен, чтобы разобраться в беспорядке?std::function
конструктор, будет очень сложно увидеть фактический вызов, особенно с оптимизацией небольших функций (так что вы на самом деле не хотите девиртуализации). Конечно в принципе все как-будто ...Есть две категории.
auto
можно избежать стирания типа. Существуют неустранимые типы (например, лямбда-выражения) и почти неузнаваемые типы (например, результатstd::bind
или другие выражения-шаблоны, подобные вещам)Без
auto
этого вам в конечном итоге придется стирать данные до чего-то вродеstd::function
. Тип стирания имеет затраты.task1
имеет издержки на стирание типа - возможное выделение кучи, сложность его выделения и накладные расходы на вызов таблицы виртуальных функций.task2
не имеет ни одного Лямбды нужно авто или другие формы удержания типа, чтобы хранить без стирания типа; другие типы могут быть настолько сложными, что им это нужно только на практике.Во-вторых, вы можете получить неправильные типы. В некоторых случаях неправильный тип будет работать на первый взгляд идеально, но приведет к копированию.
скомпилирует, если
expression()
возвращаетBar const&
илиBar
или дажеBar&
, откудаFoo
можно построитьBar
.Foo
Будет создан временный объект, а затем привязан к немуf
, и его срок жизни будет продлен до тех пор, пока онf
не исчезнет.Программист, возможно, имел в виду
Bar const& f
и не намеревался сделать копию там, но копия сделана независимо.Наиболее распространенным примером является тип
*std::map<A,B>::const_iterator
, которыйstd::pair<A const, B> const&
не являетсяstd::pair<A,B> const&
, но ошибка - это категория ошибок, которые бесшумно снижают производительность. Вы можете построитьstd::pair<A, B>
изstd::pair<const A, B>
. (Ключ на карте - const, потому что редактирование - плохая идея)Оба @Barry и @KerrekSB сначала проиллюстрировали эти два принципа в своих ответах. Это просто попытка выделить два вопроса в одном ответе с формулировкой, которая направлена на проблему, а не на пример.
источник
Существующие три ответа дают примеры , когда с помощью
auto
помогает «делает его менее вероятно, непреднамеренно pessimize» эффективно делает его «повысить производительность».Есть обратная сторона монеты. Использование
auto
с объектами, у которых есть операторы, которые не возвращают базовый объект, может привести к некорректному (все еще компилируемому и запускаемому) коду. Например, этот вопрос спрашивает, как использованиеauto
дало разные (неправильные) результаты, используя библиотеку Eigen, то есть следующие строкипривело к другому выводу. Следует признать, что это в основном связано с ленивой оценкой Eigens, но этот код / должен быть прозрачным для пользователя (библиотеки).
Хотя производительность здесь не сильно пострадала, использование
auto
во избежание непреднамеренной пессимизации может быть классифицировано как преждевременная оптимизация или, по крайней мере, неправильно;).источник