K
Sewing schrieb:
std::vector<int> vec{1,2,3};
auto e = vec.back();
vec.pop_back();
hier muss ich ne Kopie anlegen, da durch den pop der Eintrag im Speicher gelöscht wird.
std::vector<int> vec{1,2,3};
auto& e = vec.back();
vec.resize(vec.size() -1)
hier brauche ich keine Kopie
(1) Bei int s muss man keine Kopien sparen. Da solltest Du eher unnötige Hüpfereien im Speicher per Zeiger/Referenz-Verfolgung sparen.
(2) vector::resize invalidiert Referenzen. Das heißt, vec.resize(...); macht dein e zu einer baumelnden Referenz. Das ist ein Fehler.
(3) Bei int s mag dieser "Trick" augenscheinlich noch "funktionieren" (trotzdem nicht im Sinne des Erfinders!), aber bei den komplizierteren Typen, wo es gerade darauf ankommt, Kopien zu sparen, weil das Kopieren teuer ist und Destruktoren irgendwelche nicht-trivialen Aufräumarbeiten erledigen, würdest Du über dein e auf die Speicherüberseste eines schon zerstörten Objekts zugreifen! Schon zerstört im Sinne von, der Destruktor lief da schon drauf und du solltest den Speicher nicht mehr anfassen.
Sewing schrieb:
gibt es bessere/effizientere Wege?
Ja, klar. Richtig ist immer besser als falsch. Siehe sergeys Antwort, also
vector<T> vec = ...;
assert(!vec.empty());
T last = std::move(vec.back());
vec.pop_back();
So ein "Move-Request" kann in Genzfällen dazu führen, dass eine Ausnahme geworfen wird. Und wenn ein Move fehlschlägt, dann kann man sich nicht drauf verlassen, dass das Quellobjekt noch so aussieht, wie es vorher war. Wenn Dir die "strong exception safety" in diesem Fall wichtig ist, kannst Du auch std::move_if_noexcept statt std::move benutzen:
vector<T> vec = ...;
assert(!vec.empty());
T last = std::move_if_noexcept(vec.back());
vec.pop_back();