logo
Contato | Sobre...        
rebarba rebarba

Rodrigo Strauss :: Blog

follow us in feedly

C++11: auto

A palavra chave auto já existe no C++ desde os tempos mais primórdios. Ela sempre era (sim, era) um modificador de storage de variáveis. Você podia escolher o modificador auto para variáveis de armazenamento automático e register para armazenar a variável em um registrador. Esse modificador hoje em dia é implícito: se não especificado o armazenamento o compilador decide onde armazenar. De forma automática. O modificador register, até onde sei, é grande conhecido do pessoal de embarcados, que muitas vezes trabalham com recursos limitados e precisam gerenciá-los a ponto de dizer ao compilador onde a variável x será armazenada.

Interessante lembrar que a palavra chave register gera alguns efeitos colaterais, como a impossibilidade de pegar o endereço da variável com o operador &. E tem ainda o fato de que muitos compiladores modernos simplesmente não respeitam o register.

  1. //
  2. // Eu dizendo ao compilador que quero a variável a
  3. // *preferencialmente* armazenada em um registrador.
  4. //
  5. register int a = 10;
  6.  
  7. //
  8. // Eu dizendo para o compilador "eis minha variável b, enfie
  9. // onde bem entender"
  10. //
  11. auto int b = 42;
  12.  
  13. //
  14. // Quando não especifico nada, o "enfie onde quiser"
  15. // está subentendido
  16. //
  17. int c = 42;

Com o padrão C++11 o significado dessa palavra chave foi modificada. Agora ela é usada para tipar uma variável de acordo com a expressão a ela atribuída. Na linha "int a = "2 + 2", o compilador sabe que a expressão "2 + 2" retorna um tipo inteiro - na realidade o compilador sempre sabe o tipo de uma expressão em uma linguagem tipada - e pode muito bem acertar a declaração de acordo.

Esse recurso não é lá muito útil para expressões simples e pode até prejudicar a legibilidade do código, já que o leitor terá que efetuar de cabeça a mesma avaliação de expressão que o compilador fez. Ele realmente se torna útil para tipos e subtipos de classes templates, onde só o tamanho da declaração do tipo da variável pode tomar mais da metade da tela. Exemplo:

  1. //
  2. // Variável a será do tipo int
  3. //
  4. auto a = 10;
  5.  
  6. //
  7. // Variável f será do tipo double, devido à regra de promoção de tipos
  8. //
  9. auto f = 10 * 2.0;
  10.  
  11.  
  12. std::map<std::string, std::string> um_mapa;
  13.  
  14. //
  15. // Variável i será do tipo informado
  16. //
  17. std::map<std::string, std::string>::iterator i = um_mapa.begin();
  18.  
  19. //
  20. // Variável biggie_smalls terá o mesmo tipo da variável i,
  21. // mas economizando bastante espaço
  22. //
  23. auto biggie_smalls = um_mapa.begin();
  24.  
  25. //
  26. // Só pra mostrar que essa coisa toda funciona
  27. //
  28. assert(i == biggie_smalls);
  29. i = biggie_smalls;
  30.  
  31. //
  32. // ISSO NÃO FUNCIONA. É preciso haver uma atribuição para
  33. // que o compilador saiba qual o tipo
  34. //
  35. auto x; // <- error 12345: you really don't know how to use auto, do you?

Para quem programa em coisas tipo Haskell isso pode parecer óbvio. Mas já vi trocentas pessoas achando que isso é uma tentativa de transformar C++ em uma linguagem dinâmica. Então, só pra garantir:

A "nova" palavra chave auto NÃO TORNA O C++ UMA LINGUAGEM DINÂMICA. O tipo ainda é estático, você só não precisa informá-lo quando o compilador consegue deduzir isso sozinho.

Ah, isso é equivalente ao var do C# e igual ao funcionamento de declaração de variáveis da linguagem Go. E *não* é igual à declaração de variável em Python, Ruby ou Perl.

Mais um exemplo, e caso específico onde o auto é mais usado:

  1. using std::string;
  2. using std::map;
  3. using std::vector;
  4.  
  5. map<string, vector<string>> connections;
  6.  
  7. //
  8. // Como é hoje
  9. //
  10. for(map<string, vector<string>>::iterator i = connections.begin() ; i != connections.end() ; ++i)
  11. {
  12.  
  13. }
  14.  
  15. //
  16. // Muito mais fácil de ler.
  17. //
  18. for(auto i = connections.begin() ; i != connections.end() ; ++i)
  19. {
  20.  
  21. }

Em 28/11/2011 14:39, por Rodrigo Strauss


  
 
 
Comentários
Valdemar Kjær | e-mail | em 28/11/2011 | #
Pessoalmente, acho que o novo "auto" dificulta a compreensão imediata do código. Provavelmente usarei pouco - se é que usarei.
Rodrigo Strauss | website | e-mail | em 28/11/2011 | #
Nem sempre. Coloquei um outro exemplo para mostrar que em casos onde é bem óbvio o tipo, isso facilita a leitura e entendimento do código.
Ari C. Raimundo | e-mail | em 29/11/2011 | #
Rodrigo,

No mundo do .NET há quem odeie e quem ame o uso do var. Na minha opinião, o uso do var é extremamente produtivo, principalmente quando trabalhamos com LINQ.

Em C++ acredito que o auto também traz facilidades. É óbvio que o retorno do begin é um iterator, não há necessidade de escrever o tipo.

Abraços.

Ari
Wanderley Caloni | website | e-mail | em 29/11/2011 | #
O exemplo do loop com variável interna do tipo do iterator é a grande sacada, pois economiza na escrita e na leitura do código (o programador já olha direto para o begin sendo atribuído).

Agora, de forma implícita, o que o novo auto possibilita mesmo é seu uso na construção de templates.

[]s
Leandro Del Arco | em 10/12/2014 | #
Lembrando que no C++11 podemos utilizar o range-based for loop:

for(auto i : connections)
{

}

Algo a dizer?
Nome:


Site:


E-mail:


Escreva o número vinte e seis:


 Não mostre meu e-mail no site, não serve pra nada mesmo...

Comentário





Os comentários devem ser sobre assuntos relativos ao post, eu provavelmente apagarei comentários totalmente offtopic. Se quiser me enviar uma mensagem, use o formulário de contato. E não esqueça: isso é um site pessoal e eu me reservo o direito de apagar qualquer comentário ofensivo ou inapropriado.
rebarba rebarba
  ::::