C++ von den Grundlagen bis zum Profi — Folge 14
Was ist der Unterschied zwischen Kopieren und Verschieben?
Die in diesem Blog verfassten Artikel wurden mit dem Ziel erstellt, zu unterrichten. Außerdem können die Informationen im Artikel falsch sein, also seien Sie bitte vorsichtig.
Beim Einfügen eines großen Objekts in einen Vektor oder beim Zurückgeben eines Objekts von einer Funktion wird anscheinend viel kopiert. In C++ unterscheidet man zwischen dem Kopieren, bei dem der Wert unverändert vervielfältigt wird, und dem Verschieben, bei dem die Ressourcen eines Objekts übernommen werden, das nicht mehr benötigt wird.
Kopie
Durch das Kopieren wird ein neues Objekt mit denselben Werten wie das Original erstellt.
class Texture
{
public:
explicit Texture(std::vector<unsigned char> pixels)
: pixels(std::move(pixels))
{
}
private:
std::vector<unsigned char> pixels;
};
Texture original(LoadPixels());
Texture copied = original;
copiedWenn ein Vektor erstellt wird, werden auch die Daten im Vektor kopiert. Da die beiden Objekte unabhängig voneinander sind, führt eine Änderung des kopierten Objekts nicht zu einer Änderung des Originals.
Bei kleinen Werten ist der Kopieraufwand gering, Objekte mit großen Puffern oder vielen Zeichenfolgen können jedoch teuer sein.
Bewegung
Wird das Original nicht mehr verwendet, können die internen Ressourcen an ein neues Objekt weitergegeben werden.
Texture loaded(LoadPixels());
Texture equipped = std::move(loaded);
std::moveüberträgt keine Daten direkt. Wir ändern das Objekt, um es als beweglichen Wert zu behandeln, und die eigentliche Arbeit wird vom Verschiebungskonstruktor oder Verschiebungszuweisungsoperator erledigt.
bewegtloadedkönnen weiterhin zerstört und neue Werte zugewiesen werden. Sie sollten jedoch nicht erwarten, dass der interne Zustand derselbe ist wie zuvor.
loaded = Texture(LoadPixels()); //Es ist möglich, einen neuen Wert zu ersetzen.
Rule of Zero
Wenn Sie den Speicher direkt mit „Neu“ und „Löschen“ verwalten, müssen Sie den Kopierkonstruktor, die Kopierzuweisung, den Verschiebungskonstruktor, die Verschiebungszuweisung und den Destruktor gemeinsam berücksichtigen. Wenn auch nur einer falsch implementiert wird, kann es zu doppelten freien Speicherverlusten oder Speicherlecks kommen.
class CharacterData
{
public:
std::string name;
std::vector<int> learnedSkills;
std::unique_ptr<Weapon> weapon;
};
Mithilfe von Standardcontainern und Smart Pointern als Mitgliedern verwaltet jeder Typ seine eigenen Ressourcen. Diese Methode, spezielle Memberfunktionen nicht direkt zu schreiben, wird als Nullregel bezeichnet.
unique_ptr kann nicht kopiert werden; es kann nur verschoben werden. Diese Einschränkung verhindert eine versehentliche Vervielfältigung des Alleineigentums in der Kompilierungsphase.
So übergeben Sie Werte
Große Objekte, die nur lesenconst T&Wenn eine Funktion den Besitz übernimmt, wird häufig die Methode verwendet, sie als Wert zu empfangen und dann zu verschieben.
class Party
{
public:
void Add(CharacterData character)
{
members.push_back(std::move(character));
}
private:
std::vector<CharacterData> members;
};
Party party;
CharacterData warrior;
party.Add(std::move(warrior));
CharacterData hat unique_ptr als Mitglied und kann daher nicht kopiert, sondern nur verschoben werden. Wenn Sie ein vorhandenes Objekt hinzufügen, müssen Sie den Besitz mit std::move übergeben oder ein temporäres Objekt übergeben.
Das Hinzufügen von std::move überall ist nicht optimal.
Sie müssen zunächst entscheiden, ob es sich um einen Wert handelt, der kopiert werden muss, oder ob es sich um einen Wert handelt, dessen Eigentümer Sie weitergeben können. Beim Verschieben handelt es sich nicht um eine Syntax zum schnellen Kopieren, sondern vielmehr um einen Ausdruck dafür, dass man sich nach der Übertragung von Ressourcen nicht auf den Originalzustand verlässt.