C ++ auto e vs auto

88

Ao criar variáveis ​​locais, é correto usar (const) auto&ou auto?

por exemplo:

SomeClass object;
const auto result = object.SomeMethod();

ou const auto& result = object.SomeMethod();

Onde SomeMethod () retorna um valor não primitivo - talvez outro tipo definido pelo usuário. Meu entendimento é que const auto& resultestá correto, pois o resultado retornado por SomeMethod () chamaria o construtor de cópia para o tipo retornado. Por favor corrija-me se eu estiver errado.

E para tipos primitivos? Suponho que const auto sum = 1 + 2;esteja correto.

Isso também se aplica a loops for baseados em intervalo?

for(const auto& object : objects)
Rohunb
fonte
1
Eu recomendo fortemente que você leia isto: safaribooksonline.com/library/view/effective-modern-c/… Os primeiros dois capítulos são gratuitos e descrevem a dedução de tipo de modelo, que é essencialmente como autofunciona (exceto para o caso peculiar de initializer_lists, que são não deduzido em um contexto de modelo) e autodigite dedução.
vsoftco

Respostas:

102

autoe auto &&cobrem a maioria dos casos:

  • Use autoquando precisar de uma cópia local. Isso nunca produzirá uma referência. O construtor de cópia (ou movimentação) deve existir, mas pode não ser chamado, devido à otimização de elisão de cópia .

  • Use auto &&quando você não se importar se o objeto é local ou não. Tecnicamente, isso sempre produzirá uma referência, mas se o inicializador for temporário (por exemplo, a função retorna por valor), ele se comportará essencialmente como seu próprio objeto local.

    Além disso, auto &&também não garante que o objeto será modificável. Dado um constobjeto ou referência, ele irá deduzir const. No entanto, a modificabilidade é freqüentemente assumida, dado o contexto específico.

auto &e auto const &são um pouco mais específicos:

  • auto &garante que você está compartilhando a variável com outra coisa. É sempre uma referência e nunca temporária.

  • auto const &é semelhante auto &&, mas fornece acesso somente leitura.

E para tipos primitivos / não primitivos?

Não há diferença.

Isso também se aplica a loops for baseados em intervalo?

Sim. Aplicando os princípios acima,

  • Use auto &&para a capacidade de modificar e descartar valores da sequência dentro do loop. (Ou seja, a menos que o contêiner forneça uma visualização somente leitura, como std::initializer_list, nesse caso, será efetivamente um auto const &.)
  • Use auto &para modificar os valores da sequência de uma forma significativa.
  • Use auto const &para acesso somente leitura.
  • Use autopara trabalhar com cópias (modificáveis).

Você também menciona auto constsem referência. Isso funciona, mas não é muito usado porque raramente há uma vantagem para o acesso somente leitura a algo que você já possui.

Potatoswatter
fonte
Sutter diz que constness auto & tracks
Jesse Pepper
1
@JessePepper Sim. (É um pouco estranho apelar à autoridade.) Você está se referindo a uma parte específica disso?
Potatoswatter
Em essência, auto&parece ser uma boa escolha. Mas use const auto&quando quiser adicionar constância que ainda não está lá. auto&&é para encaminhamento, o que eu acho que acontece com mais frequência do que Sutter pensa. Por exemplo, você pode querer armazenar um valor de retorno auto&&e então "encaminhá-lo" para duas coisas, como std :: cout para ver o valor para depuração e também passá-lo para alguma outra função. Eu costumava usar o auto && com mais freqüência, mas fui mordido por ele uma ou duas vezes quando fazia coisas inesperadas. Eu gostaria de ter reparado melhor no que deu errado!
Jesse Pepper de
@JessePepper Sim, auto&&está relacionado a um recurso de linguagem ausente, que deve permitir que qualquer declaração seja dividida em declarações menores. A parte que falta é a extensão da vida ... Eu me esforcei bastante para consertar isso, mas ninguém percebeu. Não dê muito valor ao punditry :)
Potatoswatter
On auto const: Pode ser mais natural escrever auto const x = fn (); se você sabe que a função não retorna uma referência e deseja que o objeto x não mude, para evitar bugs ou documentar seu uso no escopo. Da mesma forma, você normalmente não escreveria: const int & x = 1; Mas auto const & fornece resultados equivalentes devido às regras de extensão de tempo de vida para referências declaradas desta forma.
Spacen Jasset
47

Sim, é correto usar autoe auto&para variáveis ​​locais. Ao obter o tipo de retorno de uma função, também é correto usar auto&. Isso também se aplica a loops for baseados em intervalo.

As regras gerais de uso autosão:

  • Escolha auto xquando você deseja trabalhar com cópias.
  • Escolha auto &xquando deseja trabalhar com itens originais e pode modificá-los.
  • Escolha auto const &xquando deseja trabalhar com itens originais e não os modificará.

Você pode ler mais sobre o especificador automático aqui .

fantasma
fonte
9

autousa o mesmo mecanismo de dedução de tipo como modelos, a única exceção de que estou ciente é a das listas brace-init, que são deduzidas por autocomo std::initializer_list, mas não deduzidas em um contexto de modelo.

auto x = expression;

funciona removendo primeiro todos os qualificadores de referência e cv do tipo da expressão do lado direito e, em seguida, combinando o tipo. Por exemplo, se você deduz const int& f(){...}então como e não .auto x = f();xint const int&

A outra forma,

auto& x = expression

não remove os qualificadores cv, portanto, usando o exemplo acima, auto& x = f()deduz xcomo const int&. As outras combinações apenas adicionam os qualificadores CV.

Se você quiser que seu tipo seja sempre deduzido com os qualificadores cv-ref, use o infame decltype(auto)em C ++ 14, que usa as decltyperegras de dedução de tipo.

Então, em poucas palavras, se você quiser cópias, use auto, se quiser referências, use auto&. Use constsempre que desejar const-ness adicional .


EDITAR Há um caso de uso adicional,

auto&& x = expression;

que usa as regras de recolhimento de referência, o mesmo que no caso de referências de encaminhamento no código do modelo. Se expressionfor um lvalue, então xé uma referência lvalue com os qualificadores cv de expression. Se expressionfor um rvalue, então xé uma referência rvalue.

vsoftco
fonte
Obrigado @Potatoswatter, editado. Na verdade, eu me pergunto sobre o cv para rvalues. Existe alguma maneira simples de testar? E como você pode ter um rvalue cv qualificado? No retorno da função, cv é descartado.
vsoftco
Não, não é descartado em retornos de função. Ele é descartado para prvalues ​​de todos os tipos escalares (C ++ 14 [e outras edições] §5 / 6). Você pode obter um usando uma chamada de função ou notação de elenco. Os valores x qualificados de Cv funcionam da mesma forma que qualquer outra coisa: auto && x = std::move< const int >( 5 );irá declarar int const && x, embora sejam raramente usados.
Potatoswatter
@Potatoswatter obrigado, você está certo, erro meu. Testei primeiro com PODs, caso em que o cv é descartado, e pensei que fosse o caso geral. Claro que não deve ser descartado, já que em geral pode-se querer preservar o cv (por exemplo, não se pode chamar uma função-membro não-const em retornos de rvalue).
vsoftco
Descartado para tipos escalares. PODs podem ser classes. De qualquer forma, é um canto difícil da intersecção do modelo de expressão e o modelo de objeto.
Potatoswatter
2

Ao criar variáveis ​​locais, é correto usar (const) auto & ou auto?

Sim. O auto nada mais é do que um tipo deduzido pelo compilador, então use referências onde você normalmente usaria referências e cópias locais (automáticas) onde você normalmente usaria cópias locais. Usar ou não uma referência é independente da dedução de tipo.

Onde SomeMethod () retorna um valor não primitivo - talvez outro tipo definido pelo usuário. Meu entendimento é que const auto & result está correto, pois o resultado retornado por SomeMethod () chamaria o construtor de cópia para o tipo retornado. Por favor corrija-me se eu estiver errado.

Legal? Sim, com o const. Melhor prática? Provavelmente não, não. Pelo menos, não com C ++ 11. Principalmente, se o valor retornado de SomeMethod () já for temporário. Você deseja aprender sobre a semântica de movimentação do C ++ 11, elisão de cópia e otimização de valor de retorno: https://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by- valor/

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=199

https://isocpp.org/wiki/faq/ctors#return-by-value-optimization

E para tipos primitivos? Presumo que const auto sum = 1 + 2; está correto.

Sim, tudo bem.

Isso também se aplica a loops for baseados em intervalo?

para (const auto & object: objetos)

Sim, isso também é bom. Eu escrevo esse tipo de código no trabalho o tempo todo.

tweej
fonte