Zoeken…


Opmerkingen

Het trefwoord auto is een typenaam die een automatisch afgeleid type vertegenwoordigt.

Het was al een gereserveerd trefwoord in C ++ 98, geërfd van C. In oude versies van C ++ kon het expliciet worden vermeld dat een variabele automatische opslagduur heeft:

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

Die oude betekenis is nu verwijderd.

Standaard automatisch voorbeeld

Het trefwoord auto biedt de automatische aftrek van het type van een variabele.

Het is vooral handig bij het omgaan met lange typenamen:

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

met bereik-gebaseerd voor lussen :

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

met lambdas :

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

om de herhaling van het type te voorkomen:

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

om verrassende en onnodige kopieën te voorkomen:

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!

De reden voor de kopie is dat het geretourneerde type eigenlijk std::pair<const int,float> !

automatische en expressiesjablonen

auto kan ook problemen veroorzaken wanneer expressiesjablonen worden gebruikt:

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.

De reden is dat operator* op valarray u een proxy-object geeft dat naar de valarray verwijst als een middel voor luie evaluatie. Door auto , creëer je een bungelende referentie. In plaats van mult had een std::valarray<int> , dan zou de code zeker 3 afdrukken.

auto, const en referenties

Het auto trefwoord zelf vertegenwoordigt een waardetype, vergelijkbaar met int of char . Het kan worden gewijzigd met het sleutelwoord const en het & -symbool om respectievelijk een const-type of een referentietype weer te geven. Deze modificaties kunnen worden gecombineerd.

In dit voorbeeld is s een waardetype (het type wordt afgeleid als std::string ), dus elke iteratie van de for lus kopieert een string van de vector naar s .

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

Als de body van de lus s wijzigt (zoals door s.append(" and stuff") aan te roepen), wordt alleen deze kopie gewijzigd, niet het oorspronkelijke lid van strings .

Aan de andere kant, als s wordt verklaard met auto& zal het een referentietype zijn (afgeleid als std::string& ), dus bij elke iteratie van de lus krijgt het een verwijzing naar een string in de vector:

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

In het lichaam van deze lus hebben wijzigingen in s rechtstreeks invloed op het element van strings waarnaar het verwijst.

Ten slotte, als s verklaard const auto& zal het een const referentie type, wat betekent dat bij elke iteratie van de lus zal een const verwijzing worden toegewezen aan een tekenreeks in de vector:

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

Binnen het lichaam van deze lus kunnen s niet worden gewijzigd (er kunnen geen niet-const-methoden op worden gebruikt).

Bij het gebruik van auto met range op basis for loops, het is over het algemeen een goede gewoonte om te gebruiken const auto& als de lus lichaam niet zal wijzigen van de structuur is een lus over, omdat dit onnodige kopieën vermijdt.

Volgend retourtype

auto wordt gebruikt in de syntaxis voor het type met retourretour:

auto main() -> int {}

wat gelijk is aan

int main() {}

Meestal handig in combinatie met decltype om parameters te gebruiken in plaats van std::declval<T> :

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

Generieke lambda (C ++ 14)

C ++ 14

C ++ 14 maakt het mogelijk om auto in lambda-argument te gebruiken

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

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

Die lambda komt grotendeels overeen met

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

en toen

lambda print;

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

auto- en proxy-objecten

Soms gedraagt auto zich niet helemaal zoals een programmeur had verwacht. Het type leidt de uitdrukking af, zelfs wanneer typeaftrek niet het juiste is om te doen.

Als een voorbeeld, wanneer proxy-objecten in de code worden gebruikt:

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

Hier flag zou niet bool , maar std::vector<bool>::reference , aangezien voor bool specialisatie van template vector de operator [] geeft een proxyobject conversie met operator operator bool gedefinieerd.

Wanneer flags.push_back(true) de container wijzigt, kan deze pseudo-referentie gaan hangen, verwijzend naar een element dat niet meer bestaat.

Het maakt ook de volgende situatie mogelijk:

void foo(bool b);

std::vector<bool> getFlags();

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

De vector wordt onmiddellijk weggegooid, dus flag is een pseudo-verwijzing naar een element dat is weggegooid. De oproep tot foo roept ongedefinieerd gedrag op.

In dit geval kunt u een variabele declareren met auto en deze initialiseren door te casten naar het type dat u wilt afleiden:

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

maar op dat moment is het eenvoudiger om auto te vervangen door bool .

Een ander geval waarbij proxy-objecten problemen kunnen veroorzaken, zijn expressiesjablonen . In dat geval zijn de sjablonen soms niet ontworpen om langer mee te gaan dan de huidige volledige expressie, en het gebruik van het proxy-object bij de volgende veroorzaakt ongedefinieerd gedrag.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow