K
Sind hier RValue-Referenzen sinnvoll? Geht so. Jedenfalls nicht so, wie sie aktuell angewendet wurden. Man kann's auch ganz ohne machen. Warum auch nicht?
#include <vector>
#include <string>
#include <utility>
struct Data {
std::string str;
int i;
};
class Second {
public:
Second(Data d) : data(std::move(d)){}
private:
Data data;
};
class First {
public:
First(Data d) : second(std::move(d)){}
private:
Second second;
};
int main() {
First test(Data{"test",42});
return 0;
}
(ungetestet)
Wenn ich hier keinen Fehler gemacht habe, wird hier nichts unnötig kopiert, nur ein paar mal "gemovet".
Rvalue-Referenzen bzgl Move-Semantik sind dazu da, den Move-Constructor schreiben zu können. Sonst sind das stinknormale Referenzen. Es gibt nur zwei Sonderheiten (und eine dritte, dich ich verschweige, weil ich Dich nicht durcheinander bringen will): Du kannst eine Rvalue-Referenz nur mit etwas Initialisieren, was sich entweder auf ein temporäres Objekt oder auf ein anderes Objekt beziehen wird, dessen Zustand verändert werden darf, ohne dass das jemanden stören würde. Mit std::move kann man so etwas zB ausdrücken, sollte man aber auch nur machen, wenn es nicht sowieso schon überflüssig wäre. Der zweite Unterschied liegt bei einer Rvalue-Referenz als Rückgabe-Typ einer Funktion. Das sollte man zwar bei eigenen Funktionen vermeiden (!!!), aber du solltest wissen, dass ein solcher Funktionsaufruf ein Rvalue-Ausdruck und kein Lvalue-Ausdruck darstellt. std::move und std::forward nutzen dies aus.
Nachtrag: Data wird hier jeweils "per Wert" an die Konstruktoren übergeben. Je nachdem, was Du für eine Quelle hast (ist das Argument ein Lvalue oder Rvalue?) wird hier entweder der Kopier- oder der Move-Konstruktor ausgewählt. Der Parameter 'd' ist ein Lvalue-Ausdruck, der aber später nicht mehr benötigt wird. Daher wird der nächste Konstruktor mit std::move(d) als Argument aufgerufen, was eine unnötige Kopie verhindert; denn Data bekommt automatisch einen Move-Construktor, der wich für Rvalue-Quellen verantwortlich fühlt.