Im Zuweisungsoperator einer Klasse müssen Sie normalerweise überprüfen, ob das zugewiesene Objekt das aufrufende Objekt ist, damit Sie nichts vermasseln:
Class& Class::operator=(const Class& rhs) {
if (this != &rhs) {
// do the assignment
}
return *this;
}
Benötigen Sie dasselbe für den Verschiebungszuweisungsoperator? Gibt es jemals eine Situation, in this == &rhs
der dies wahr wäre?
? Class::operator=(Class&& rhs) {
?
}
c++
c++11
move-semantics
move-assignment-operator
Seth Carnegie
quelle
quelle
A a; a = std::move(a);
.std::move
ist normal. Berücksichtigen Sie dann das Aliasing. Wenn Sie sich tief in einem Aufrufstapel befinden und einen Verweis aufT
und einen weiteren Verweis aufT
... haben, werden Sie hier nach der Identität suchen? Möchten Sie den ersten Aufruf (oder die ersten Aufrufe) finden, bei denen die Dokumentation, dass Sie nicht dasselbe Argument zweimal übergeben können, statisch beweist, dass diese beiden Verweise keinen Alias darstellen? Oder werden Sie dafür sorgen, dass die Selbstzuweisung einfach funktioniert?std::sort
oderstd::shuffle
- jedes Mal, wenn Sie dasi
dritte und dasj
dritte Element eines Arrays austauschen, ohne diesi != j
vorher zu überprüfen . (std::swap
wird in Bezug auf dieAntworten:
Wow, hier gibt es einfach so viel aufzuräumen ...
Erstens ist das Kopieren und Austauschen nicht immer der richtige Weg, um die Kopierzuweisung zu implementieren. Mit ziemlicher Sicherheit
dumb_array
ist dies eine suboptimale Lösung.Die Verwendung von Kopieren und Tauschen ist
dumb_array
ein klassisches Beispiel dafür, wie die teuerste Operation mit den vollsten Funktionen in der unteren Ebene platziert wird. Es ist perfekt für Kunden, die die volle Funktionalität wünschen und bereit sind, die Leistungsstrafe zu zahlen. Sie bekommen genau das, was sie wollen.Es ist jedoch katastrophal für Kunden, die nicht die volle Funktionalität benötigen und stattdessen die höchste Leistung suchen. Für sie
dumb_array
ist es nur eine weitere Software, die sie neu schreiben müssen, weil sie zu langsam ist. Wäredumb_array
es anders gestaltet worden, hätte es beide Kunden ohne Kompromisse für beide Kunden zufrieden stellen können.Der Schlüssel zur Zufriedenheit beider Clients besteht darin, die schnellsten Vorgänge auf der niedrigsten Ebene zu erstellen und anschließend eine API hinzuzufügen, um umfassendere Funktionen zu höheren Kosten zu erhalten. Dh du brauchst die starke Ausnahmegarantie, gut, du bezahlst dafür. Du brauchst es nicht Hier ist eine schnellere Lösung.
Lassen Sie uns konkret werden: Hier ist der schnelle, grundlegende Ausnahmegarantie-Operator für die Zuweisung von Kopien für
dumb_array
:Erläuterung:
Eines der teureren Dinge, die Sie mit moderner Hardware tun können, ist ein Ausflug auf den Haufen. Alles, was Sie tun können, um einen Ausflug auf den Haufen zu vermeiden, ist Zeit und Mühe, die gut angelegt sind. Clients von
dumb_array
möchten möglicherweise häufig Arrays derselben Größe zuweisen. Und wenn sie es tun, müssen Sie nur einmemcpy
(versteckt unterstd::copy
) tun . Sie möchten kein neues Array derselben Größe zuweisen und dann das alte Array derselben Größe freigeben!Nun zu Ihren Kunden, die tatsächlich eine starke Ausnahmesicherheit wünschen:
Oder wenn Sie die Verschiebungszuweisung in C ++ 11 nutzen möchten, sollte dies sein:
Wenn
dumb_array
die Clients Wert auf Geschwindigkeit legen, sollten sie die anrufenoperator=
. Wenn sie eine starke Ausnahmesicherheit benötigen, können sie generische Algorithmen aufrufen, die für eine Vielzahl von Objekten funktionieren und nur einmal implementiert werden müssen.Nun zurück zur ursprünglichen Frage (die zu diesem Zeitpunkt einen Typ-O hat):
Dies ist eigentlich eine kontroverse Frage. Einige werden ja sagen, absolut, andere werden nein sagen.
Meine persönliche Meinung ist nein, Sie brauchen diesen Scheck nicht.
Begründung:
Wenn ein Objekt an eine r-Wert-Referenz gebunden wird, ist dies eines von zwei Dingen:
Wenn Sie einen Verweis auf ein Objekt haben, das tatsächlich temporär ist, haben Sie per Definition einen eindeutigen Verweis auf dieses Objekt. Es kann unmöglich von irgendwo anders in Ihrem gesamten Programm referenziert werden. Dh
this == &temporary
ist nicht möglich .Wenn Ihr Kunde Sie angelogen und Ihnen versprochen hat, dass Sie eine vorübergehende Behandlung erhalten, wenn Sie dies nicht tun, liegt es in der Verantwortung des Kunden, sicherzustellen, dass Sie sich nicht darum kümmern müssen. Wenn Sie wirklich vorsichtig sein möchten, glaube ich, dass dies eine bessere Implementierung wäre:
Dh Wenn Sie sind eine selbst Referenz übergeben, das ist ein Fehler auf Seiten des Kunden , die behoben werden sollen.
Der Vollständigkeit halber ist hier ein Verschiebungszuweisungsoperator für
dumb_array
:Im typischen Anwendungsfall der Verschiebungszuweisung handelt
*this
es sich um ein verschobenes Objekt unddelete [] mArray;
sollte daher ein No-Op sein. Es ist wichtig, dass Implementierungen das Löschen auf einem Nullptr so schnell wie möglich machen.Vorbehalt:
Einige werden argumentieren, dass dies
swap(x, x)
eine gute Idee oder nur ein notwendiges Übel ist. Und dies kann, wenn der Swap zum Standard-Swap wechselt, eine Selbstbewegungszuweisung verursachen.Ich bin nicht einverstanden , dass
swap(x, x)
ist immer eine gute Idee. Wenn es in meinem eigenen Code gefunden wird, betrachte ich es als Leistungsfehler und behebe es.swap(x, x)
Wenn Sie dies jedoch zulassen möchten, müssen Sie sich darüber im Klaren sein , dass Self-Move-Assignemnet nur für einen Verschiebungswert verwendet wird. Und in unseremdumb_array
Beispiel ist dies vollkommen harmlos, wenn wir die Behauptung einfach weglassen oder sie auf den Fall beschränken, aus dem wir uns entfernt haben:Wenn Sie zwei verschobene (leere) selbst zuweisen
dumb_array
, tun Sie nichts Falsches, außer nutzlose Anweisungen in Ihr Programm einzufügen. Dieselbe Beobachtung kann für die überwiegende Mehrheit der Objekte gemacht werden.<
Aktualisieren>
Ich habe über dieses Problem noch etwas nachgedacht und meine Position etwas geändert. Ich bin jetzt der Meinung, dass die Zuweisung tolerant gegenüber der Selbstzuweisung sein sollte, aber dass die Post-Bedingungen für die Zuweisung von Kopien und die Zuweisung von Verschiebungen unterschiedlich sind:
Für die Zuordnung von Kopien:
man sollte eine Nachbedingung haben, dass der Wert von
y
nicht geändert werden sollte. Wenn&x == &y
dann diese Nachbedingung übersetzt wird in: Selbstkopiezuweisung sollte keinen Einfluss auf den Wert von habenx
.Für die Zugzuweisung:
man sollte eine Nachbedingung haben,
y
die einen gültigen, aber nicht spezifizierten Zustand hat. Wenn&x == &y
dann diese Nachbedingung übersetzt wird:x
hat einen gültigen, aber nicht spezifizierten Zustand. Das heißt, die Selbstbewegungsaufgabe muss kein No-Op sein. Aber es sollte nicht abstürzen. Diese Nachbedingung steht im Einklang mit der Erlaubnisswap(x, x)
, nur zu arbeiten:Das obige funktioniert, solange
x = std::move(x)
es nicht abstürzt. Es kannx
in jedem gültigen, aber nicht spezifizierten Zustand belassen werden.Ich sehe drei Möglichkeiten, den Verschiebungszuweisungsoperator zu programmieren
dumb_array
, um dies zu erreichen:Die obige Umsetzung toleriert Selbstzuweisung, sondern
*this
undother
ein Null-sized Array nach der Selbst bewegt Zuordnung am Ende wird, unabhängig davon , was der ursprüngliche Wert*this
ist. Das ist in Ordnung.Die obige Implementierung toleriert die Selbstzuweisung genauso wie der Kopierzuweisungsoperator, indem sie zu einem No-Op gemacht wird. Das ist auch gut so.
Das Obige ist nur in Ordnung, wenn
dumb_array
es keine Ressourcen enthält, die "sofort" zerstört werden sollten. Wenn zum Beispiel die einzige Ressource Speicher ist, ist das oben Genannte in Ordnung. Wenndumb_array
möglicherweise Mutex-Sperren oder der geöffnete Status von Dateien vorhanden sein könnten, könnte der Client vernünftigerweise erwarten, dass diese Ressourcen auf der linken Seite der Verschiebungszuweisung sofort freigegeben werden, und daher könnte diese Implementierung problematisch sein.Die Kosten für das erste sind zwei zusätzliche Geschäfte. Die Kosten für die Sekunde sind Test und Verzweigung. Beide arbeiten. Beide erfüllen alle Anforderungen von Tabelle 22 MoveAssignable-Anforderungen im C ++ 11-Standard. Der dritte funktioniert auch modulo das Nicht-Speicher-Ressourcen-Problem.
Alle drei Implementierungen können je nach Hardware unterschiedliche Kosten verursachen: Wie teuer ist eine Niederlassung? Gibt es viele oder nur sehr wenige Register?
Das Mitnehmen ist, dass die Selbstverschiebungszuweisung im Gegensatz zur Selbstkopierzuweisung nicht den aktuellen Wert beibehalten muss.
<
/Aktualisieren>
Eine letzte (hoffentlich) Bearbeitung, die von Luc Dantons Kommentar inspiriert wurde:
Wenn Sie eine Klasse auf hoher Ebene schreiben, die den Speicher nicht direkt verwaltet (aber möglicherweise Basen oder Mitglieder hat, die dies tun), ist die beste Implementierung der Verschiebungszuweisung häufig:
Dadurch werden jede Basis und jedes Mitglied nacheinander zugewiesen und es wird kein
this != &other
Scheck hinzugefügt. Dies bietet Ihnen die höchste Leistung und grundlegende Ausnahmesicherheit, vorausgesetzt, dass keine Invarianten zwischen Ihren Basen und Mitgliedern beibehalten werden müssen. Zeigen Sie Ihren Kunden, die eine starke Ausnahmesicherheit fordern, diesestrong_assign
.quelle
std::swap(x,x)
, warum sollte ich dann darauf vertrauen, dass kompliziertere Vorgänge korrekt ausgeführt werden?std::swap(x,x)
geht, funktioniert es nur , wennx = std::move(x)
ein nicht spezifiziertes Ergebnis erzielt wird. Versuch es! Du musst mir nicht glauben.swap
funktioniert so lange wiex = move(x)
Blätterx
in einem beweglichen Zustand. Und diestd::copy
/std::move
-Algorithmen sind so definiert, dass sie bereits auf No-Op-Kopien ein undefiniertes Verhalten erzeugen (autsch; der 20-Jährigememmove
macht den trivialen Fall richtig,std::move
tut es aber nicht!). Ich denke also, ich habe noch nicht an einen "Slam Dunk" zur Selbstzuweisung gedacht. Aber offensichtlich ist Selbstzuweisung etwas, was im realen Code häufig vorkommt, unabhängig davon, ob der Standard ihn gesegnet hat oder nicht.Erstens haben Sie die Signatur des Verschiebungszuweisungsoperators falsch verstanden. Da Bewegungen Ressourcen aus dem Quellobjekt stehlen, muss die Quelle eine
const
Referenz ohne r-Wert sein.Beachten Sie, dass Sie immer noch über eine (nicht
const
) l- Wert-Referenz zurückkehren.Bei beiden Arten der direkten Zuweisung besteht der Standard nicht darin, die Selbstzuweisung zu überprüfen, sondern sicherzustellen, dass eine Selbstzuweisung keinen Absturz verursacht. Im Allgemeinen tut
x = x
odery = std::move(y)
ruft niemand explizit auf , aber Aliasing, insbesondere durch mehrere Funktionen, kann zu Selbstzuweisungen führena = b
oder dazu führenc = std::move(d)
. Eine explizite Überprüfung der Selbstzuweisung, dhthis == &rhs
, dass das Fleisch der Funktion übersprungen wird, wenn sie wahr ist, ist eine Möglichkeit, die Sicherheit der Selbstzuweisung zu gewährleisten. Dies ist jedoch eine der schlimmsten Möglichkeiten, da ein (hoffentlich) seltener Fall optimiert wird, während es eine Anti-Optimierung für den häufigeren Fall darstellt (aufgrund von Verzweigungen und möglicherweise Cache-Fehlern).Wenn (mindestens) einer der Operanden ein direkt temporäres Objekt ist, kann es niemals zu einem Selbstzuweisungsszenario kommen. Einige Leute befürworten die Annahme dieses Falls und optimieren den Code so sehr, dass der Code selbstmörderisch dumm wird, wenn die Annahme falsch ist. Ich sage, dass es unverantwortlich ist, die gleiche Objektprüfung auf Benutzer abzulegen. Wir machen dieses Argument nicht für die Zuweisung von Kopien; Warum die Position für die Bewegungszuweisung umkehren?
Lassen Sie uns ein Beispiel machen, das von einem anderen Befragten geändert wurde:
Diese Kopierzuweisung behandelt die Selbstzuweisung ohne explizite Prüfung ordnungsgemäß. Wenn sich die Quell- und Zielgrößen unterscheiden, werden die Freigabe und die Neuzuweisung vor dem Kopieren vorgenommen. Andernfalls wird nur das Kopieren durchgeführt. Die Selbstzuweisung erhält keinen optimierten Pfad, sondern wird in denselben Pfad verschoben, in dem die Quell- und Zielgröße gleich beginnen. Das Kopieren ist technisch nicht erforderlich, wenn die beiden Objekte gleichwertig sind (auch wenn sie dasselbe Objekt sind), aber das ist der Preis, wenn keine Gleichheitsprüfung (wert- oder adressbezogen) durchgeführt wird, da diese Prüfung selbst am meisten Verschwendung wäre der ganzen Zeit. Beachten Sie, dass die Selbstzuweisung von Objekten hier eine Reihe von Selbstzuweisungen auf Elementebene verursacht. Der Elementtyp muss dafür sicher sein.
Wie das Quellbeispiel bietet diese Zuweisung die grundlegende Sicherheitsgarantie für Ausnahmen. Wenn Sie die starke Garantie wünschen, verwenden Sie den Unified-Assignment-Operator aus der ursprünglichen Copy and Swap- Abfrage, der sowohl die Copy- als auch die Move-Zuweisung behandelt. In diesem Beispiel geht es jedoch darum, die Sicherheit um einen Rang zu verringern, um an Geschwindigkeit zu gewinnen. (Übrigens gehen wir davon aus, dass die Werte der einzelnen Elemente unabhängig sind; dass es keine invariante Einschränkung gibt, die einige Werte im Vergleich zu anderen einschränkt.)
Schauen wir uns eine Verschiebungszuweisung für denselben Typ an:
Ein austauschbarer Typ, der angepasst werden muss, sollte eine Funktion mit zwei Argumenten haben, die
swap
im selben Namespace wie der Typ aufgerufen wird . (Durch die Namespace-Einschränkung können nicht qualifizierte Aufrufe zum Arbeiten ausgetauscht werden.) Ein Containertyp sollte auch eine öffentlicheswap
Member-Funktion hinzufügen , die den Standardcontainern entspricht. Wenn ein Mitgliedswap
nicht bereitgestellt wird, muss die freie Funktionswap
wahrscheinlich als Freund des austauschbaren Typs markiert werden. Wenn Sie die zu verwendenden Moves anpassenswap
, müssen Sie Ihren eigenen Swap-Code angeben. Der Standardcode ruft den Verschiebungscode des Typs auf, was zu einer unendlichen gegenseitigen Rekursion für verschiebungsangepasste Typen führen würde.Wie Destruktoren sollten Swap-Funktionen und Verschiebungsoperationen, wenn möglich, niemals ausgelöst und wahrscheinlich als solche markiert werden (in C ++ 11). Standardbibliothekstypen und -routinen verfügen über Optimierungen für nicht wegwerfbare Bewegungstypen.
Diese erste Version der Umzugszuweisung erfüllt den Grundvertrag. Die Ressourcenmarkierungen der Quelle werden an das Zielobjekt übertragen. Die alten Ressourcen werden nicht verloren gehen, da das Quellobjekt sie jetzt verwaltet. Das Quellobjekt befindet sich in einem verwendbaren Zustand, in dem weitere Operationen, einschließlich Zuweisung und Zerstörung, darauf angewendet werden können.
Beachten Sie, dass diese Verschiebungszuweisung automatisch für die Selbstzuweisung sicher ist, da der
swap
Anruf erfolgt. Es ist auch stark ausnahmesicher. Das Problem ist die unnötige Ressourcenbindung. Die alten Ressourcen für das Ziel werden konzeptionell nicht mehr benötigt, aber hier sind sie nur noch vorhanden, damit das Quellobjekt gültig bleiben kann. Wenn die geplante Zerstörung des Quellobjekts weit entfernt ist, verschwenden wir Ressourcenraum, oder schlimmer noch, wenn der gesamte Ressourcenraum begrenzt ist und andere Ressourcenanträge gestellt werden, bevor das (neue) Quellobjekt offiziell stirbt.Dieses Problem hat den umstrittenen aktuellen Guru-Rat bezüglich der Selbstausrichtung während der Zuweisung von Bewegungen verursacht. Die Art und Weise, eine Zugzuweisung zu schreiben, ohne Ressourcen zu belassen, ist wie folgt:
Die Quelle wird auf die Standardbedingungen zurückgesetzt, während die alten Zielressourcen zerstört werden. Im Fall der Selbstzuweisung begeht Ihr aktuelles Objekt Selbstmord. Die Hauptmethode besteht darin, den Aktionscode mit einem
if(this != &other)
Block zu umgeben oder ihn zu verschrauben und den Kunden eineassert(this != &other)
erste Zeile zu geben (wenn Sie sich gut fühlen).Eine Alternative besteht darin, zu untersuchen, wie die Zuweisung von Kopien ohne einheitliche Zuweisung stark ausnahmesicher gemacht werden kann, und sie auf die Zuweisung von Verschiebungen anzuwenden:
Wann
other
undthis
sind verschieden,other
wird durch den Umzug nach geleerttemp
und bleibt so. Dannthis
verliert seine alten Ressourcen ,temp
während sich die Ressourcen ursprünglich aus Beständenother
. Dann werden die alten Ressourcenthis
getötet, wenn dies dertemp
Fall ist.Wenn Selbstzuweisung stattfindet
other
,temp
leert sichthis
auch das Entleeren in . Dann erhält das Zielobjekt seine Ressourcen zurück, wenntemp
undthis
tauscht. Der Tod vontemp
behauptet ein leeres Objekt, das praktisch ein No-Op sein sollte. Dasthis
/other
Objekt behält seine Ressourcen.Die Zugzuweisung sollte niemals geworfen werden, solange Zugbewegung und Tausch ebenfalls möglich sind. Die Kosten, um auch während der Selbstzuweisung sicher zu sein, sind ein paar weitere Anweisungen für Typen auf niedriger Ebene, die durch den Freigabeaufruf überflutet werden sollten.
quelle
delete
Ihren zweiten Codeblock aufrufen ?std::copy
verursacht undefiniertes Verhalten, wenn sich die Quell- und Zielbereiche überschneiden (einschließlich des Falls, wenn sie zusammenfallen). Siehe C ++ 14 [alg.copy] / 3.Ich bin im Lager derer, die sichere Operatoren für die Selbstzuweisung wollen, aber keine Selbstzuweisungsprüfungen in den Implementierungen von schreiben möchten
operator=
. Und in der Tat möchte ich überhaupt nicht implementierenoperator=
, ich möchte, dass das Standardverhalten "sofort" funktioniert. Die besten Sondermitglieder sind diejenigen, die kostenlos kommen.Davon abgesehen werden die im Standard enthaltenen MoveAssignable-Anforderungen wie folgt beschrieben (ab 17.6.3.1 Anforderungen an Vorlagenargumente [Utility.arg.requirements], n3290):
wobei die Platzhalter wie
t
folgt beschrieben werden: " [ist ein] modifizierbarer Wert vom Typ T;" und "rv
ist ein Wert vom Typ T;". Beachten Sie, dass dies Anforderungen an die Typen sind, die als Argumente für die Vorlagen der Standardbibliothek verwendet werden. Wenn ich jedoch an anderer Stelle im Standard nachschaue, stelle ich fest, dass jede Anforderung an die Verschiebungszuweisung dieser ähnlich ist.Das heißt,
a = std::move(a)
das muss "sicher" sein. Wenn Sie einen Identitätstest benötigen (z. B.this != &other
), dann machen Sie ihn, sonst können Sie Ihre Objekte nicht einmal hineinlegenstd::vector
! (Es sei denn , Sie nicht die Mitglieder verwenden / Operationen , die erfordern MoveAssignable, aber macht nichts , dass.) Beachten Sie, dass mit dem vorherigen Beispiela = std::move(a)
, dannthis == &other
wird in der Tat halten.quelle
a = std::move(a)
Nicht-Arbeiten dazu führen würde, dass eine Klasse nicht funktioniertstd::vector
? Beispiel?std::vector<T>::erase
ist nur zulässig, wennT
MoveAssignable aktiviert ist. (Abgesehen von IIRC wurden einige MoveAssignable-Anforderungen stattdessen in C ++ 14 auf MoveInsertable gelockert.)T
muss also MoveAssignable sein, aber warum sollte manerase()
jemals davon abhängen, ein Element in sich selbst zu verschieben ?Da Ihre aktuelle
operator=
Funktion geschrieben ist, können Sie, da Sie das Argument rvalue-reference erstellt habenconst
, die Zeiger auf keinen Fall "stehlen" und die Werte der eingehenden rvalue-Referenz ändern. Sie können sie einfach nicht ändern konnte nur daraus lesen. Ich würde nur dann ein Problem sehen, wenn Sie anfangen würden,delete
Zeiger usw. in Ihremthis
Objekt aufzurufen , wie Sie es bei einer normalen lvaue-Referenzmethode tun würdenoperator=
, aber diese Art besiegt den Punkt der rvalue-Version ... dh es würde Es scheint überflüssig zu sein, die rvalue-Version zu verwenden, um im Grunde die gleichen Operationen auszuführen, die normalerweise einerconst
-lvalue-operator=
Methode überlassen werden.Wenn Sie nun definiert haben
operator=
, dass Sie eine Nicht-const
Wert-Referenz verwenden sollen, konnte ich nur sehen, dass eine Prüfung erforderlich ist, wenn Sie dasthis
Objekt an eine Funktion übergeben haben, die absichtlich eine Wert-Referenz anstelle einer temporären Referenz zurückgegeben hat.Angenommen, jemand hat versucht, eine
operator+
Funktion zu schreiben , und eine Mischung aus r-Wert-Referenzen und l-Wert-Referenzen verwendet, um zu verhindern, dass während einer gestapelten Additionsoperation für den Objekttyp zusätzliche Temporäre erstellt werden:Nach meinem Verständnis von rvalue-Referenzen wird davon abgeraten, das oben Gesagte zu tun (dh Sie sollten nur eine temporäre, keine rvalue-Referenz zurückgeben). Wenn dies jedoch noch jemand tun würde, sollten Sie dies überprüfen Stellen Sie sicher, dass die eingehende rWert-Referenz nicht auf dasselbe Objekt wie der
this
Zeiger verweist .quelle
const
, nur daraus lesen können, also die einzige Notwendigkeit Eine Überprüfung wäre, wenn Sie sich dazu entschließenoperator=(const T&&)
, dieselbe Neuinitialisierung durchzuführen, diethis
Sie bei einer typischenoperator=(const T&)
Methode und nicht bei einer Operation im Swap-Stil durchführen würden (dh Zeiger stehlen usw., anstatt tiefe Kopien zu erstellen).Meine Antwort lautet immer noch, dass die Zuweisung von Zügen nicht gegen Selbstzuweisung gesichert sein muss, sondern eine andere Erklärung hat. Betrachten Sie std :: unique_ptr. Wenn ich eine implementieren würde, würde ich so etwas tun:
Wenn Sie sich Scott Meyers ansehen , der dies erklärt , macht er etwas Ähnliches. (Wenn Sie wandern, warum nicht tauschen - es hat ein zusätzliches Schreiben). Und dies ist nicht sicher für die Selbstzuweisung.
Manchmal ist das unglücklich. Ziehen Sie in Betracht, alle geraden Zahlen aus dem Vektor zu entfernen:
Dies ist für ganze Zahlen in Ordnung, aber ich glaube nicht, dass Sie so etwas mit Verschiebungssemantik zum Laufen bringen können.
Abschließend: Die Zuordnung zum Objekt selbst zu verschieben ist nicht in Ordnung und Sie müssen darauf achten.
Kleines Update.
swap(x, x)
sie funktionieren sollte. Algorithmen lieben diese Dinge! Es ist immer schön, wenn ein Eckkoffer gerade funktioniert. (Und ich muss noch einen Fall sehen, in dem es nicht kostenlos ist. Das heißt aber nicht, dass es nicht existiert).unique_ptr& operator=(unique_ptr&& u) noexcept { reset(u.release()); ...}
Es ist sicher für die Zuweisung von Selbstverschiebungen.quelle
Es gibt eine Situation, an die ich denken kann (dies == rhs). Für diese Aussage: Myclass obj; std :: move (obj) = std :: move (obj)
quelle