auto
может помочь производительности, избегая неявных неявных преобразований . Пример, который я считаю убедительным, следующий.
std::map<Key, Val> m;
// ...
for (std::pair<Key, Val> const& item : m) {
// do stuff
}
Видишь ошибку? Здесь мы думаем, что элегантно берем каждый элемент на карте с помощью константной ссылки и используем новое выражение диапазона для того, чтобы прояснить наше намерение, но на самом деле мы копируем каждый элемент. Это происходит потому , что std::map<Key, Val>::value_type
это std::pair<const Key, Val>
не std::pair<Key, Val>
. Таким образом, когда мы (неявно) имеем:
std::pair<Key, Val> const& item = *iter;
Вместо того, чтобы брать ссылку на существующий объект и оставлять его при этом, мы должны выполнить преобразование типа. Вам разрешено принимать константную ссылку на объект (или временный) другого типа при условии, что доступно неявное преобразование, например:
int const& i = 2.0; // perfectly OK
Преобразование типов является допустимым неявным преобразованием по той же причине, по которой вы можете преобразовать a const Key
в a Key
, но мы должны создать временный объект нового типа, чтобы учесть это. Таким образом, наш цикл эффективно:
std::pair<Key, Val> __tmp = *iter; // construct a temporary of the correct type
std::pair<Key, Val> const& item = __tmp; // then, take a reference to it
(Конечно, на самом деле нет __tmp
объекта, он есть просто для иллюстрации, на самом деле неназванный временный объект просто обязан item
для своей жизни).
Просто меняется на:
for (auto const& item : m) {
// do stuff
}
просто сэкономил нам кучу копий - теперь ссылочный тип соответствует типу инициализатора, поэтому временное преобразование или преобразование не требуется, мы можем просто сделать прямую ссылку.