Sök…


Anmärkningar

Nyckelordet auto är ett typnamn som representerar en automatiskt härledd typ.

Det var redan ett reserverat nyckelord i C ++ 98, ärvt från C. I gamla versioner av C ++ kan det användas för att uttryckligen ange att en variabel har automatisk lagringsvaraktighet:

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

Den gamla meningen har nu tagits bort.

Grundläggande automatisk prov

Nyckelordet auto ger automatisk avdrag för typen av en variabel.

Det är särskilt bekvämt när man handlar med långa typnamn:

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" );

med områdebaserade för slingor :

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

med lambdas :

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

för att undvika upprepning av typen:

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

för att undvika överraskande och onödiga kopior:

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!

Anledningen till kopian är att den returnerade typen faktiskt är std::pair<const int,float> !

auto- och expressionsmallar

auto kan också orsaka problem där expressionsmallar spelas in:

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.

Anledningen är att operator*valarray ger dig ett proxyobjekt som hänvisar till valarray som ett medel för lat utvärdering. Genom att använda auto skapar du en dinglande referens. Istället för att mult hade returnerat en std::valarray<int> , skulle koden definitivt skriva ut 3.

auto, const och referenser

Det auto nyckelordet i sig representerar en värdetyp, liknande int eller char . Det kan modifieras med const nyckelordet och symbolen & att representera en konsttyp respektive en referenstyp. Dessa modifierare kan kombineras.

I detta exempel är s en värdetyp (dess typ kommer att sluts som std::string ), så varje iteration av for loop kopierar en sträng från vektorn till s .

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

Om slingans kropp ändrar s (t.ex. genom att ringa s.append(" and stuff") ) kommer endast den här kopian att ändras, inte den ursprungliga medlemmen i strings .

Å andra sidan, om s deklareras med auto& det kommer att vara en referenstyp (utgår från att vara std::string& ), så på varje iteration av slingan kommer den att tilldelas en referens till en sträng i vektorn:

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

I kroppen på denna slinga kommer ändringar av s direkt att påverka elementet i strings som det refererar till.

Slutligen, om s förklaras const auto& , kommer det att vara en const-referenstyp, vilket betyder att på varje iteration av slingan tilldelas en const-referens till en sträng i vektorn:

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

Inuti kroppen hos denna slinga, s kan inte ändras (dvs. inga icke-const metoder kan anropas på det).

När du använder auto med områdebaserade for slingor är det i allmänhet god praxis att använda const auto& om slingkroppen inte kommer att ändra strukturen som slingras, eftersom detta undviker onödiga kopior.

Släpningstyp

auto används i syntaxen för efterföljande returtyp:

auto main() -> int {}

vilket motsvarar

int main() {}

Mycket användbart i kombination med decltype att använda parametrar istället för std::declval<T> :

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

Generisk lambda (C ++ 14)

C ++ 14

C ++ 14 tillåter att använda auto i lambda-argument

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

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

Den lambda motsvarar mestadels

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

och då

lambda print;

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

auto- och proxyobjekt

Ibland kan auto uppträda inte riktigt som förväntat av en programmerare. Den typen härleder uttrycket, även om typavdrag inte är rätt att göra.

Som exempel, när proxyobjekt används i koden:

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

Här flag skulle inte bool , men std::vector<bool>::reference , eftersom det för bool specialisering av mall vector den operator [] returnerar ett proxyobjekt med omvandlingsoperator operator bool definierats.

När flags.push_back(true) modifierar behållaren, kan denna pseudo-referens hamna dinglande, med hänvisning till ett element som inte längre finns.

Det gör också nästa situation möjlig:

void foo(bool b);

std::vector<bool> getFlags();

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

vector kasseras omedelbart, så flag är en pseudo-referens till ett element som har kasserats. Uppmaningen till foo åberopar odefinierat beteende.

I fall som detta kan du förklara en variabel med auto och initiera den genom att kasta till den typ du vill dras från:

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

men vid den tidpunkten är det mer meningsfullt att helt enkelt byta ut auto med bool .

Ett annat fall där proxyobjekt kan orsaka problem är expressionsmallar . I så fall är mallarna ibland inte utformade för att sträcka sig utöver det nuvarande fulluttrycket för effektivitetsskull, och att använda proxyobjektet på nästa orsakar odefinierat beteende.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow