ProgrammatieC++ ontwikkelaar

Wat zijn 'lvalue' en 'rvalue' in C++? Verklaar hun verschillen, manieren van doorgeven aan functies en waarom rvalue-referenties zijn ontstaan.

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

In C++ is lvalue (left value) een expressie die verwijst naar een object in het geheugen, dat een naam heeft en waarnaar kan worden verwezen (bijvoorbeeld een variabele). rvalue (right value) is een tijdelijke waarde, zonder naam, en is geen object in de traditionele zin (bijvoorbeeld het resultaat van a + b, literalen zoals 5).

Lvalue kan worden gepakt als adres, maar rvalue kan dat niet (tot de introductie van rvalue-referenties). Voor het doorgeven ervan aan functies bestaan:

  • Gewone referenties: void foo(const std::string& s); — accepteren lvalue en rvalue.
  • Lvalue-referenties: void bar(std::string& s); — accepteren alleen lvalue.
  • Rvalue-referenties (C++11+): void baz(std::string&& s); — accepteren alleen rvalue.

Voorbeeld:

void takeValue(std::string& s) { } // lvalue void takeRValue(std::string&& s) { } // rvalue std::string s = "hello"; takeValue(s); // OK, lvalue takeRValue(std::string("hi")); // OK, rvalue

Rvalue-referenties zijn nodig voor een effectieve overdracht van tijdelijke objecten, voornamelijk voor move-semantiek, om middelen te verplaatsen in plaats van ze te kopiëren.

Strikvraag

Welke soort referentie (lvalue of rvalue) zal de expressie std::move(obj) verkrijgen? Tot welke categorie zal het object zelf behoren na het toepassen van std::move?

Antwoord:

std::move(obj) geeft altijd een rvalue-referentie (T&&) terug, maar het object zelf blijft een lvalue, gewoonweg toegepaste expliciete conversie. Hierna moet je uiterst voorzichtig met het object omgaan (het kan in een onbepaalde, maar geldige toestand zijn).

Voorbeeld:

std::string s = "data"; std::string d = std::move(s); // d krijgt de data van s, s is nu leeg

Voorbeelden van echte fouten door onbekendheid met de nuances van het onderwerp.


Verhaal

In een groot project gaf een van de ontwikkelaars tijdelijke objecten door via een lvalue-referentie T& (in plaats van T&& of const T&). Dit leidde tot compilatiefouten en suboptimale kopieën — move-semantiek werd niet gebruikt, wat leidde tot een prestatievermindering van 40%.


Verhaal

In de frontend-engine werd std::move verkeerd toegepast op variabelen die daarna opnieuw werden gebruikt. Dit resulteerde in "vernietigde" variabelen, leidend tot crashende applicaties en renders.


Verhaal

In de serialisatiebibliotheek werden containers van het type std::vector<T> als lvalue naar een functie doorgegeven, terwijl een move werd verwacht. In plaats van te verplaatsen, werden dure kopieën gemaakt van een groot aantal elementen, wat de serialisatietijd voor grote arrays aanzienlijk verslechterde.