auto
pode ajudar no desempenho, evitando conversões implícitas silenciosas . Um exemplo que considero atraente é o seguinte.
std::map<Key, Val> m;
// ...
for (std::pair<Key, Val> const& item : m) {
// do stuff
}
Vê o bug? Aqui estamos, pensando que estamos usando elegantemente todos os itens do mapa por referência const e usando a nova expressão range-for para tornar nossa intenção clara, mas na verdade estamos copiando todos os elementos. Isto é porque std::map<Key, Val>::value_type
é std::pair<const Key, Val>
, não std::pair<Key, Val>
. Assim, quando nós (implicitamente) temos:
std::pair<Key, Val> const& item = *iter;
Em vez de pegar uma referência a um objeto existente e deixá-lo assim, precisamos fazer uma conversão de tipo. Você tem permissão para fazer uma referência const a um objeto (ou temporário) de um tipo diferente, desde que haja uma conversão implícita disponível, por exemplo:
int const& i = 2.0; // perfectly OK
A conversão de tipo é uma conversão implícita permitida pelo mesmo motivo pelo qual você pode converter a const Key
em a Key
, mas precisamos construir um temporário do novo tipo para permitir isso. Assim, efetivamente nosso loop:
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
(É claro que não há realmente um __tmp
objeto, ele está lá apenas para ilustração; na realidade, o temporário sem nome está vinculado apenas item
por toda a sua vida).
Apenas alterando para:
for (auto const& item : m) {
// do stuff
}
nos salvou uma tonelada de cópias - agora o tipo referenciado corresponde ao tipo do inicializador, portanto, nenhuma conversão ou temporária é necessária, podemos apenas fazer uma referência direta.