Ricerca…


Osservazioni

La parola chiave auto è un typename che rappresenta un tipo dedotto automaticamente.

Era già una parola chiave riservata in C ++ 98, ereditata da C. Nelle vecchie versioni di C ++, poteva essere usata per dichiarare esplicitamente che una variabile ha una durata di archiviazione automatica:

int main()
{
  auto int i = 5; // removing auto has no effect
}

Quel vecchio significato è ora rimosso.

Campione automatico di base

La parola chiave auto fornisce l'auto-deduzione del tipo di una variabile.

È particolarmente utile quando si ha a che fare con nomi di caratteri lunghi:

std::map< std::string, std::shared_ptr< Widget > > table;
// C++98
std::map< std::string, std::shared_ptr< Widget > >::iterator i = table.find( "42" );
// C++11/14/17
auto j = table.find( "42" );

con loop basati su range :

vector<int> v = {0, 1, 2, 3, 4, 5};
for(auto n: v)
    std::cout << n << ' ';

con lambda :

auto f = [](){ std::cout << "lambda\n"; };
f();        

per evitare la ripetizione del tipo:

auto w = std::make_shared< Widget >();

per evitare copie sorprendenti e non necessarie:

auto myMap = std::map<int,float>();
myMap.emplace(1,3.14);

std::pair<int,float> const& firstPair2 = *myMap.begin();  // copy!
auto const& firstPair = *myMap.begin();  // no copy!

Il motivo della copia è che il tipo restituito è in realtà std::pair<const int,float> !

Modelli auto ed espressioni

auto può anche causare problemi quando entrano in gioco i modelli di espressione:

auto mult(int c) {
    return c * std::valarray<int>{1};
}

auto v = mult(3);
std::cout << v[0]; // some value that could be, but almost certainly is not, 3.

Il motivo è che l' operator* su valarray fornisce un oggetto proxy che fa riferimento al valarray come mezzo di valutazione lazy. Usando l' auto , stai creando un riferimento ciondolante. Invece di mult aveva restituito uno std::valarray<int> , quindi il codice avrebbe sicuramente stampato 3.

auto, const e riferimenti

La parola chiave auto per sé rappresenta un tipo di valore, simile a int o char . Può essere modificato con la parola chiave const e il simbolo & per rappresentare rispettivamente un tipo const o un tipo di riferimento. Questi modificatori possono essere combinati.

In questo esempio, s è un tipo di valore (il suo tipo sarà dedotto come std::string ), quindi ogni iterazione del ciclo for copia una stringa dal vettore in s .

std::vector<std::string> strings = { "stuff", "things", "misc" };
for(auto s : strings) {
    std::cout << s << std::endl;
}

Se il corpo del loop modifica s (ad esempio chiamando s.append(" and stuff") ), solo questa copia verrà modificata, non il membro originale delle strings .

D'altra parte, se s è dichiarato con auto& sarà un tipo di riferimento (dedotto per essere std::string& ), così ad ogni iterazione del ciclo verrà assegnato un riferimento ad una stringa nel vettore:

for(auto& s : strings) {
    std::cout << s << std::endl;
}

Nel corpo di questo ciclo, le modifiche a s influenzeranno direttamente l'elemento delle strings cui fa riferimento.

Infine, se s è dichiarato const auto& , sarà un tipo di riferimento const, nel senso che ad ogni iterazione del ciclo verrà assegnato un riferimento const a una stringa nel vettore:

for(const auto& s : strings) {
    std::cout << s << std::endl;
}

All'interno del corpo di questo ciclo, s non può essere modificato (cioè non può essere chiamato alcun metodo non const).

Quando si utilizza l' auto con cicli basati for intervalli, è generalmente buona norma usare const auto& se il corpo del loop non modificherà la struttura in loop, poiché evita copie non necessarie.

Tipo di ritorno finale

auto viene utilizzato nella sintassi per il tipo di ritorno finale:

auto main() -> int {}

che è equivalente a

int main() {}

Molto utile combinato con decltype per usare i parametri invece di std::declval<T> :

template <typename T1, typename T2>
auto Add(const T1& lhs, const T2& rhs) -> decltype(lhs + rhs) { return lhs + rhs; }

Lambda generico (C ++ 14)

C ++ 14

C ++ 14 consente di utilizzare auto argomento auto in lambda

auto print = [](const auto& arg) { std::cout << arg << std::endl; };

print(42);
print("hello world");

Quella lambda è per lo più equivalente a

struct lambda {
    template <typename T>
    auto operator ()(const T& arg) const {
        std::cout << arg << std::endl;
    }
};

e poi

lambda print;

print(42);
print("hello world");

oggetti auto e proxy

A volte l' auto può comportarsi in modo non proprio come previsto da un programmatore. Il tipo deduce l'espressione, anche quando la deduzione del tipo non è la cosa giusta da fare.

Ad esempio, quando gli oggetti proxy sono utilizzati nel codice:

std::vector<bool> flags{true, true, false};
auto flag = flags[0];
flags.push_back(true);

Qui flag sarebbe bool , ma std::vector<bool>::reference , poiché per la specializzazione bool del vector template l' operator [] restituisce un oggetto proxy con operator bool conversione definito.

Quando flags.push_back(true) modifica il contenitore, questo pseudo-riferimento potrebbe finire in sospeso, facendo riferimento a un elemento che non esiste più.

Rende anche possibile la prossima situazione:

void foo(bool b);

std::vector<bool> getFlags();

auto flag = getFlags()[5];
foo(flag);

Il vector viene scartato immediatamente, quindi flag è uno pseudo-riferimento a un elemento che è stato scartato. La chiamata a foo richiama un comportamento indefinito.

In casi come questo è possibile dichiarare una variabile con auto e inizializzarla eseguendo il casting sul tipo che si desidera dedurre:

auto flag = static_cast<bool>(getFlags()[5]);

ma a quel punto, semplicemente sostituire l' auto con il bool ha più senso.

Un altro caso in cui gli oggetti proxy possono causare problemi sono i modelli di espressione . In tal caso, i modelli a volte non sono progettati per durare oltre l'espressione completa corrente per motivi di efficienza e l'utilizzo dell'oggetto proxy sul prossimo causa un comportamento non definito.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow