schönes c++?
-
otze schrieb:
Ein Objekt ist swappable, wenn für jeden Member gilt: er ist swappable. Merke: ist ein Objekt kopierbar, ist es swappable.
ok, und was macht ein objekt nichtkopierbar? wenn es zu komplex ist, d.h. viele referenzen bzw. pointer auf andere objekte hat, die wiederum welche auf irgendwas haben usw? und wieso wird swap mit kopieren gleichgesetzt? bei einer kopie entsteht ja ein duplikat, beim swap höchstens temporär, in der swapfunktion. wenn man von objekten dauerhafte kopien macht, dann besteht ja die gefahr, dass irgendwelche 1:1-beziehungen ungewollt vervielfacht werden, was ja bei einem swap nicht der fall ist.
Nexus schrieb:
Sobald man aber eine sinnvolle Tauschfunktion einrichtet, wird ein Tausch nicht nur exceptionsicher, sondern sehr performant.
aha, man muss tauschfunktionen selber schreiben (was die klasse swappable macht), sonst tut swap nix, bzw. macht einfach ein paar 'memcpys', ne?
Nexus schrieb:
Das ist ja das Gute: Wenn du z.B. zwei Container mit mehreren Millionen Elementen hast, kannst du diese in konstanter Zeit austauschen. Das läuft fast aufs Gleiche wie ein Zeigertausch hinaus...
kann doch garnicht sein. wenn der tausch zweier objekte die zeit t braucht, dann braucht's um 2 mio. objekte zu tauschen 1000000*t. wenn nicht, wie funktioniert dieser trick?
Nexus schrieb:
Sei doch bitte in Zukunft etwas mehr auf diese Weise interessiert, solche Diskussionen mag ich nämlich.
hihi, du fühlst dich dann wie daheim, im C++ unterforum *fg*
keine angst, meine einstellung zu C++ bleibt weiterhin extrem kritisch (wüsste auch nicht, was das ändern könnte), aber ein paar hintergrundinfos zu erfragen, kann ja nicht schaden und ausserdem kann mir in diesem thread dann auch keiner vorwerfen, dass ich nicht 'über den tellerrand' schauen will.
-
Bei der swap Geschichte hatte ich jetzt den Überblick verloren, aber die meisten Sprachen haben dazu bereits den operator = eingeführt.
-
;fricky schrieb:
ok, und was macht ein objekt nichtkopierbar?
Prinzipiell wenig. Man muss aber selbst nen copy-ctor schreiben, wenn beim kopieren spezielle Logik gebraucht wird. Zum Beispiel kopieren Container nicht einfach die Speicher sondern die dahinter liegenden Speicherbereiche - aber das solltest du ja auch wissen ;).
wenn es zu komplex ist, d.h. viele referenzen bzw. pointer auf andere objekte hat, die wiederum welche auf irgendwas haben usw?
Ja, wenn man beim kopieren die Abhängigkeiten nicht mehr auflösen kann, hat man ein Problem. Aber dann hat man ein grundsätzliches Problem, das weit über swap hinaus geht.
und wieso wird swap mit kopieren gleichgesetzt? bei einer kopie entsteht ja ein duplikat, beim swap höchstens temporär, in der swapfunktion. wenn man von objekten dauerhafte kopien macht, dann besteht ja die gefahr, dass irgendwelche 1:1-beziehungen ungewollt vervielfacht werden, was ja bei einem swap nicht der fall ist.
Und eben das temporäre Duplikat ist das Problem. Das Duplikat muss ordnungsgemäß erstellt und weiter kopiert werden können. Zusätzlich muss sich das Duplikat am Ende von swap selbst wieder aufräumen. Kann man das alles nicht garantieren, ist das Objekt aber trotzdem logisch swappable, dann muss man sich eine überladene Version für swap basteln - genauso, wie wenn die zweifache Kopie beim swap zu teuer ist und wesentlich einfacher erzeugt werden könnte.
kann doch garnicht sein. wenn der tausch zweier objekte die zeit t braucht, dann braucht's um 2 mio. objekte zu tauschen 1000000*t. wenn nicht, wie funktioniert dieser trick?
Wir tauschen Zeiger.
Ich halte die Diskussion ab hier aber ziemlich metalastig, da swap sicher keine Ruhmesseite von C++ ist. Natürlich kann man das was da oben steht alles machen - nur spucken einem die Regeln der Funktionsüberladung bei Templates in die suppe. Deswegen gibt es keinen swap(std::vector<T>& a,std::vector<T>& b) sondern nur ein std::vector<T>::swap(std::vector<T>&). Man muss sich also im konkreten Anwendungsfall sein eigenes swap mit einem konkreten Typen überladen, wenn man swap auf containern schnell machen möchte.
//edit der Punkt ist allerdings: auch wnen swap nicht perfekt gelöst ist, ist es im Vergleich mit anderen Sprachen ein sehr gutes swap. Es gab irgendwo eine Website, die solche "universellen" Funktionen für verschiedene Sprachen verglichen hat (swap, min/max etc) und im Vergleich stand C++ dann auch gar nicht so schlecht da.
-
;fricky schrieb:
ok, und was macht ein objekt nichtkopierbar? wenn es zu komplex ist, d.h. viele referenzen bzw. pointer auf andere objekte hat, die wiederum welche auf irgendwas haben usw?
Nicht unbedingt. Wenn die Klassen sinnvoll geschrieben sind (d.h. jede ist selbst für eine tiefe Kopie der Objekte zuständig, auf die sie verweist), ist das kein Problem. Aber es gibt eben Objekte, deren Kopie semantisch nicht sinnvoll ist, zum Beispiel Streams oder Fenster-Instanzen.
;fricky schrieb:
und wieso wird swap mit kopieren gleichgesetzt?
Es wird ja nicht gleichgesetzt. Man kann Objekte eher austauschen, als man sie kopieren kann, weil eben eine Kopie eine vergleichsweise komplizierte Operation ist und eine neue Entität erzeugt, während bei einem Tausch sozusagen nur die Sichtweise auf die Objekte geändert wird.
;fricky schrieb:
aha, man muss tauschfunktionen selber schreiben (was die klasse swappable macht), sonst tut swap nix, bzw. macht einfach ein paar 'memcpys', ne?
Nicht
memcpy()
, weil das wieder byteweise wäre. Es wird normal kopiert (byteweise bei PODs, über den Kopierkonstruktor bei Nicht-POD-Klassen). In vielen Fällen ist es auch gar kein Problem, wenn Klassen keine Tauschfunktion mitbringen, da eine Zuweisung verhältnismässig günstig ist und keine Exceptions oder sonstige Fehlschläge auftreten können.;fricky schrieb:
kann doch garnicht sein. wenn der tausch zweier objekte die zeit t braucht, dann braucht's um 2 mio. objekte zu tauschen 1000000*t. wenn nicht, wie funktioniert dieser trick?
Du tauschst nicht alle Elemente, sondern z.B. nur zwei Zeiger auf dynamisch allokierte Arrays, die die Elemente enthalten.
;fricky schrieb:
hihi, du fühlst dich dann wie daheim, im C++ unterforum *fg*
keine angst, meine einstellung zu C++ bleibt weiterhin extrem kritisch (wüsste auch nicht, was das ändern könnte), aber ein paar hintergrundinfos zu erfragen, kann ja nicht schaden und ausserdem kann mir in diesem thread dann auch keiner vorwerfen, dass ich nicht 'über den tellerrand' schauen will.Ich habe nichts gegen Kritik an C++, sofern sie begründet ist und es nicht nur ums Flamen geht. Im C++-Forum habe ich übrigens auch schon Teile kritisiert.
Du darfst auch ruhig deine Einstellung behalten. Ab und zu sind ja wirklich sinnvolle Diskussionen mit dir möglich, warum nicht etwas öfter?
player4245 schrieb:
Bei der swap Geschichte hatte ich jetzt den Überblick verloren, aber die meisten Sprachen haben dazu bereits den operator = eingeführt.
Zuweisung und Tausch ist nicht das Gleiche. Nach der Zuweisung gibt es zwei gleiche Objekte. Oder meinst du den Dreieckstausch, der über Zuweisungsoperatoren implementiert ist?
-
es ging doch um den tausch von 2 werten. Und Klassen bieten doch mit Kopierkonstruktor und Operatorüberladung (operator=) alles an was das Herz begehrt.
-
otze schrieb:
Natürlich kann man das was da oben steht alles machen - nur spucken einem die Regeln der Funktionsüberladung bei Templates in die suppe. Deswegen gibt es keinen swap(std::vector<T>& a,std::vector<T>& b) sondern nur ein std::vector<T>::swap(std::vector<T>&). Man muss sich also im konkreten Anwendungsfall sein eigenes swap mit einem konkreten Typen überladen, wenn man swap auf containern schnell machen möchte.
Das stimmt so nicht. Funktionsüberladung erlaubt das Tauschen von Templates (bzw. von deren Instanziierungen). Für die Standardcontainer ist
std::swap()
ebenfalls überladen. Was du vielleicht meinst, ist der C++-Standard, der eine Überladung vonstd::swap()
für eigene Typen verbietet. Nur Template-Spezialisierung ist erlaubt, und die geht bei Funktionen eben nicht partiell. Deshalb sollte man im Allgemeinen auch nichtstd::swap()
aufrufen, sondern ADL mitwirken lassen und sich evtl. sowas basteln:template <typename T> void adl_swap(T& lhs, T& rhs) { using std::swap; swap(lhs, rhs); }
otze schrieb:
Es gab irgendwo eine Website, die solche "universellen" Funktionen für verschiedene Sprachen verglichen hat (swap, min/max etc) und im Vergleich stand C++ dann auch gar nicht so schlecht da.
Wenn du die zufällig wieder mal finden solltest, würde mich das noch interessieren.
player4245 schrieb:
es ging doch um den tausch von 2 werten. Und Klassen bieten doch mit Kopierkonstruktor und Operatorüberladung (operator=) alles an was das Herz begehrt.
Eben nicht, das wurde in diesem Thread inzwischen aber ein paar Male erklärt.
-
Nexus schrieb:
Das stimmt so nicht.
Aye. Da hat sich was in meinen Hirnwindung verklemmt. Ich habe wohl einige Zeit die Eigenschaften Überladung und Spezialisierung durcheinandergeworfen - wird mal wieder Zeit, dass ich wieder eigenen Code schreibe, bei dem ich wieder templates nutzen kann und nicht nur den komischen Polymorphiekram...
Was du vielleicht meinst, ist der C++-Standard, der eine Überladung von
std::swap()
für eigene Typen verbietet.Was aber kein problem sein sollte, da eigenerNamespace::swap erlaubt ist. und bei swap(Objekt) wird dann der Namespace korrekt durch den Compiler ermittelt - Pluspunkt für namespaces.
Wenn du die zufällig wieder mal finden solltest, würde mich das noch interessieren.
Ich vertraue drauf, dass jemand anders diese Seite wieder postet, denn von hier hatte ich den link
-
otze schrieb:
Was aber kein problem sein sollte, da eigenerNamespace::swap erlaubt ist. und bei swap(Objekt) wird dann der Namespace korrekt durch den Compiler ermittelt - Pluspunkt für namespaces.
Ist teilweise doch ein Problem, da einige Programmierer (leider sogar Entwickler von Standardbibliotheks-Implementierungen, siehe Algorithmus
std::iter_swap()
) durchgehendstd::swap()
mit expliziter Angabe des Namensraumes verwenden, was natürlich alle Hoffnung auf ADL zerstört.Doch wenn man Namensräume richtig anwendet, hat man in der Tat ein mächtiges Werkzeug in der Hand. Argument Dependent Lookup zähle ich sogar als weitere Art der Polymorphie.
-
Wie oft wird der Konstruktor aufgerufen?
#include<iostream> #include<string> using std::string; using std::cout; using std::cin; using std::endl; void pause() { std::cin.get(); } class Box { public: Box(const string& element) : _content(element) { cout << "Call Box Constructor" << endl; } const string& to_string() { return _content; } private: string _content; }; int main() { auto box1 = new Box("Hello"); auto box2 = new Box("World"); std::swap(box1, box2); cout << box1->to_string() << endl; cout << box2->to_string() << endl; pause(); return 0; }
-
Zeus, dafür brauchst du wie gesagt nicht einmal Zeiger (und auch keine Memory Leaks ;)). Denn dein Beispiel zeigt nicht wirklich, worin der Vorteil von
swap()
besteht -- nämlich nicht nur darin, 3 Zuweisungen nicht explizit schreiben zu müssen.class box { public: explicit box(const std::string& str) : m_str(str) { } void swap(box& other) { swap(m_str, other.m_str); } const std::string& to_string() const { return m_str; } private: std::string m_str; }; int main() { box a("erste Box"); box b("die 2. Box"); a.swap(b); std::cout << a.to_string() << std::endl; std::cout << b.to_string() << std::endl; }
-
otze schrieb:
Zum Beispiel kopieren Container nicht einfach die Speicher sondern die dahinter liegenden Speicherbereiche - aber das solltest du ja auch wissen.
eigentlich nicht. ich verstehe nicht was du mit speicher vs. dahinter liegende speicherbereiche meinst, höchstens so:
speicher == speichert die pointer
dahinterliegend == das, worauf die pointer zeigen.otze schrieb:
kann doch garnicht sein. wenn der tausch zweier objekte die zeit t braucht, dann braucht's um 2 mio. objekte zu tauschen 1000000*t. wenn nicht, wie funktioniert dieser trick?
Wir tauschen Zeiger.
ok, also doch keine hexerei, hihi. so'n zeiger- bzw. referenztausch ist z.b. in Java die einzige 'normale' swap-möglichkeit für objekte. objektinhalte selbst durch die gegend zu schieben, ist ja eigentlich auch ziemlich doof. mir war so, dass in c++ immer viel zeug 'vollautomatisiert' kopiert wird (value-semantik), aber offenbar nimmt man davon doch abstand, wenn's zuviel des guten wird *fg*
Nexus schrieb:
;fricky schrieb:
ok, und was macht ein objekt nichtkopierbar? wenn es zu komplex ist, d.h. viele referenzen bzw. pointer auf andere objekte hat, die wiederum welche auf irgendwas haben usw?
Nicht unbedingt. Wenn die Klassen sinnvoll geschrieben sind (d.h. jede ist selbst für eine tiefe Kopie der Objekte zuständig, auf die sie verweist), ist das kein Problem.
heisst das, dass jede klasse ihre besitzende objekte, von denen referenzierte objekte usw. selbst kopieren muss? gibt es in C++ kein äquivalent zum Java 'Serializable'-interface bzw. eine art kaskadierendes copy/swap usw? wenn nicht, kann das ja eine ziemliche fummelei werden.
-
player4245 schrieb:
es ging doch um den tausch von 2 werten. Und Klassen bieten doch mit Kopierkonstruktor und Operatorüberladung (operator=) alles an was das Herz begehrt.
jetzt fängt der wieder mit dem C++ bashing an
-
Ich will ja nicht vorlaut sein, ich hab Werktags nachts halb 3 ja auch nichts besseres zu tun als hier zu posten, aber wie man sich seitenlang um so einen irrelevanten pfusch streiten kann will mir nicht in den Kopf gehen.
-
@ohne: jetzt fängt der wieder mit dem spam an
übrigens hat java dafür clone ...oh nein jetzt bashe ich auch noch java
-
;fricky schrieb:
otze schrieb:
Zum Beispiel kopieren Container nicht einfach die Speicher sondern die dahinter liegenden Speicherbereiche - aber das solltest du ja auch wissen.
eigentlich nicht. ich verstehe nicht was du mit speicher vs. dahinter liegende speicherbereiche meinst, höchstens so:
speicher == speichert die pointer
dahinterliegend == das, worauf die pointer zeigen.Flache Kopie / Tiefe Kopie
otze schrieb:
kann doch garnicht sein. wenn der tausch zweier objekte die zeit t braucht, dann braucht's um 2 mio. objekte zu tauschen 1000000*t. wenn nicht, wie funktioniert dieser trick?
Wir tauschen Zeiger.
ok, also doch keine hexerei, hihi. so'n zeiger- bzw. referenztausch ist z.b. in Java die einzige 'normale' swap-möglichkeit für objekte. objektinhalte selbst durch die gegend zu schieben, ist ja eigentlich auch ziemlich doof. mir war so, dass in c++ immer viel zeug 'vollautomatisiert' kopiert wird (value-semantik), aber offenbar nimmt man davon doch abstand, wenn's zuviel des guten wird *fg*
Ne ne ne.
Du kannst kein Referenz Swap in Java machen (also direkt auf den zu tauschenden Objekten) - denn damit hast du massig wilde Zeiger. Furchtbar sowas.Und du scheinst value semantik nicht verstanden zu haben. Denn value semantik erlaubt dir ja erst so sachen wie swap. Swap geht deshalb in Java garnicht vernünftig. Du musst in Java jeden Fall von swap händisch implementieren und kannst nix generisches wie in C++ machen... Nur mit Reflection und das ist ja echt nicht ideal...
heisst das, dass jede klasse ihre besitzende objekte, von denen referenzierte objekte usw. selbst kopieren muss? gibt es in C++ kein äquivalent zum Java 'Serializable'-interface bzw. eine art kaskadierendes copy/swap usw? wenn nicht, kann das ja eine ziemliche fummelei werden.
Nein, heisst es nicht.
Serializable ist in Java ein super Beispiel wie eine Implementierung nicht aussehen soll, aber das ist ein anderes Thema.
In C++ tut man einfach keinen Code schreiben und lässt den Compiler die tiefen kopien machen. Im Gegensatz zu Javas clone() funktioniert das sogar ohne Bauchweh
-
Wie bekommst du die wilde Zeiger hin?
-
Shade Of Mine schrieb:
Ne ne ne.
Du kannst kein Referenz Swap in Java machen (also direkt auf den zu tauschenden Objekten) - denn damit hast du massig wilde Zeiger. Furchtbar sowas.Und du scheinst value semantik nicht verstanden zu haben. Denn value semantik erlaubt dir ja erst so sachen wie swap. Swap geht deshalb in Java garnicht vernünftig. Du musst in Java jeden Fall von swap händisch implementieren und kannst nix generisches wie in C++ machen... Nur mit Reflection und das ist ja echt nicht ideal...
Bei C++ haben es die meisten ja schon kapiert, dass man nicht wie mit Java programmieren soll. Aber wieso wollt ihr dann Java so wie mit C++ programmieren?
heisst das, dass jede klasse ihre besitzende objekte, von denen referenzierte objekte usw. selbst kopieren muss? gibt es in C++ kein äquivalent zum Java 'Serializable'-interface bzw. eine art kaskadierendes copy/swap usw? wenn nicht, kann das ja eine ziemliche fummelei werden.
Nein, heisst es nicht.
Serializable ist in Java ein super Beispiel wie eine Implementierung nicht aussehen soll, aber das ist ein anderes Thema.
In C++ tut man einfach keinen Code schreiben und lässt den Compiler die tiefen kopien machen.Warum haben die sich dann Copy-Swap usw. extra für C++ ausgedacht? Weil mans nicht braucht, da der Compiler ja so tolle tiefe Kopien von Strings, Listen usw. macht. Klar doch.
-
Shade Of Mine schrieb:
Du kannst kein Referenz Swap in Java machen (also direkt auf den zu tauschenden Objekten)
^^das sagt ja auch keiner. ausserdem hat mir immer noch keiner erklärt, wozu dieser direkte objekttausch überhaupt gut ist, wenn man doch refererenzen fröhlich rumswappen kann (in Java, wenn sie sich in einem array befinden).
Shade Of Mine schrieb:
- denn damit hast du massig wilde Zeiger. Furchtbar sowas.
wie jetzt? also manchmal werfen deine postings mehr fragen auf als sie beantworten.
Shade Of Mine schrieb:
Denn value semantik erlaubt dir ja erst so sachen wie swap. Swap geht deshalb in Java garnicht vernünftig. Du musst in Java jeden Fall von swap händisch implementieren und kannst nix generisches wie in C++ machen... Nur mit Reflection und das ist ja echt nicht ideal...
wer will den auch sowas in Java machen? höchstens einer, der's von C++ kennt und noch nicht lange in Java programmiert.
Shade Of Mine schrieb:
Serializable ist in Java ein super Beispiel wie eine Implementierung nicht aussehen soll, aber das ist ein anderes Thema.
egal, funzt aber prima.
Shade Of Mine schrieb:
In C++ tut man einfach keinen Code schreiben und lässt den Compiler die tiefen kopien machen. Im Gegensatz zu Javas clone() funktioniert das sogar ohne Bauchweh
tiefe kopien von komplexen objekten aber nur, wenn die objekte auch mitspielen (mit angepsstem zuweisungs-op, copy-contruktur und so), ansonsten ist es ähnlich dem clone() von Java.