Wie swap in eigener Klasse machen?
-
camper schrieb:
Überflüssig, wenn du sowieso bereits ein normales swap im Namensraum der Klasse hast. Aufteilen oder nur Header bleibt dir überlassen. Wenn alles im Header steht, muss die Funktion ausserdem als inline deklariert werden.
Ja, es ist überflüssig es war nur Zusatz drin, falls ich es mal so machen möchte.
camper schrieb:
Weder für std::move noch für std::sort ist eine Überladung basierend auf den Argumenttypen vorgesehen - es wäre auch kaum sinnvoll. std::cout ist ein Objekt.
Ah, daran habe ich nicht gedacht.
OK, als allerletztes, wenn ich nun friend swap in meiner Klasse (im header habe). Habe ich dann so richtig in der (.cpp) auf sie verwiesen?
-
Benutzernamer schrieb:
OK, als allerletztes, wenn ich nun friend swap in meiner Klasse (im header habe). Habe ich dann so richtig in der (.cpp) auf sie verwiesen?
Das ist richtig so. Eine friend-Funktion, die erst durch die friend-Deklaration erstmals deklariert wird, lebt in dem Namensraum, der die jewelige Klasse umgibt, in deren Definition die friend-Deklaration auftaucht.
-
Es ist doch noch eine, ...
Im falle B erbt von A, dann müsste doch bei dem swap noch ein using std::swap über dem swap von Basisklasse A. Wurde zwar schon definiert aber falls das nicht der Fall ist und oder die Funktion noch einmal umdefinieren will.
friend void swap(B& x, B& y) { using std::swap; swap(static_cast<A&>(x), static_cast<A&>(y)); // Basisklassenteile von x und y //using std::swap; //oder doch nur hier swap(x.asdf, y.asdf); }
-
hmm, ich habe es mal in einem größeren Programm probiert. Habe eigentlich alles so gemacht wie beschrieben (friend swap und 2 moves als Member, und bei Vererbung auf ursprüngliche Klasse verwiesen). Einziger Unterschied is, dass die Klassen pointer auf Speicherbereiche haben. Es sollte doch auch gehen wenn man move auf die pointer macht, und dann den Ursprung 0 setzt.
Die Objekte bekommen einen pointer auf einen Bereich eines int* (intpointer), kopieren diesen Bereich (länge m) und werden schließlich in Obj-vektor vect gespeichert. Vor der Änderung mit move und swap hat alles funktioniert. Danach geht es nur noch, wenn ich alle Elemente des vektors erst erstelle und dann dem vektor hinzufüge.
//so führt es zum segmentation fault for(int i = 0; n < num; i++) vect[i] = Obj{intpointer + i * m, m}; //so gehts jedoch for(int i = 0; n < num; i++){ Obj temp = Obj{intpointer + i * m}; vect[i] = temp; }
Das Initialisieren klapp mit beiden Varianten (d.h. Programm läuft weiter). Später wird ein sort gemacht und dabei geht irgendetwas schief, wenn ich die erste Variante verwende.
"Obj" erbt von Obj0 und hat nur ein paar normale Variablen extra. Obj0 erbt wiederurm von einer anderen Klasse Objbase und hat noch einen extra pointer. Objbase speichert dann die Daten (die an intpointer + i * m liegen) in einer eigenen Kopie davon. Falls ich die moves aus einer Klasse entferne gehen auch beide Varianten.Die Funktionen sehen in etwa so aus:
//class Obj : public Obj0 Obj& operator= (Obj&& oobj) { if(this == &oobj) return *this; Obj0::operator=(std::move(oobj)); return *this; } Obj(Obj&& oobj):Obj0(std::move(oobj)){ } friend void swap(Obj& o1, Obj&o2){ if(&o1 == &o2) return; using std::swap; swap(static_cast<Obj0&>(o1), static_cast<Obj0&>(o2)); } //class Obj0 : public Objbase //int* otherintpointer; Obj0& operator= (Obj0&& oobj) { if(this == &oobj) return *this; Objbase::operator=(std::move(oobj)); otherintpointer = std::move(oobj.otherintpointer); oobj.otherintpointer = NULL; return *this; } Obj0(Obj0&& oobj): Objbase(std::move(oobj)), otherintpointer(std::move(oobj.otherintpointer)) { oobj.otherintpointer = NULL; } friend void swap(Obj0& o1, Obj0&o2){ if(&o1 == &o2) return; using std::swap; swap(static_cast<Objbase&>(o1), static_cast<Objbase&>(o2)); swap(o1.otherintpointer , o2.otherintpointer); } //class Objbase //int* intpointer; int m; Objbase& operator= (Objbase&& oobj) { if(this == &oobj) return *this; m = std::move( oobj.m); intpointer = std::move( oobj.intpointer); oobj.intpointer == NULL; return *this; } Objbase(Objbase&& oobj) { m = std::move( oobj.m); intpointer = std::move( oobj.intpointer); oobj.intpointer == NULL; } void swap(Objbase& o1, Objbase&o2){ if(&o1 == &o2) return; using std::swap; swap(o1.intpointer , o2.intpointer); swap(o1.m , o2.m); }
Was ist bzw. könnte falsch sein?
-
Hi,
move wird auf rvalue referencen ausgeführt. Also auf temporäre Objekte. Wenn st std::move(object) machst, sagst du damit auch, dass du object nicht mehr brauchst. Da musst du nix mehr auf null pointer setzen.
In deinem Besipiel, verwendest du auch einmal den Copy Constructor und einmal den Move Constructor. Und der Copy geht offenbar (bzw. führt nicht zu einem Absturz).
Bei move auf Klassen mit dynamischen Speicherstellen musst du aufpassen, dass du nicht nur den Zeiger umhängst und dann eventuell ins nichts zeigst. Der einfachste (und meiner Meinung nach beste) Weg ist, Smart Pointer zu verwenden. Da funktioniert move ohne Probleme. (Dafür musst du beim unique_ptr überlegen was du beim Copy Constructor machen willst).
Hier nochmal eine ganz gute Erklärung zum Copy & Swap Ideom: https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
Edit: Was willst du in Zeile 23 machen?
-
Meine Empfehlung:
immer using std::swap + unqualifizierten Aufruf von swap.Bzw. eine Komponente die das zusammenfasst. Boosts swap wäre zu erwähnen.
Edit: Was willst du in Zeile 23 machen?
Er will wohl die Zuweisung rekursiv auf die Basisklassen anwenden. Genau wegen solcher Komplikationen lässt man spezielle Memberfunktionen i.d.R. fast ausschließlich implizit definieren.