schönes c++?



  • ;fricky schrieb:

    kennt einer eigentlich ein sinnvolles beispiel, bei dem objekte selbst geswappt werden müssen?

    naja z.b. beim sortieren von arrays etc.

    eigentlich reichts doch immer, wenn man referenzen rumschubst anstatt objektinhalte auszutauschen.

    in C++ arbeitet man wo es geht mit value-semantics, und nicht mit reference-semantics, weil's einfach schneller ist (weil keine/weniger dynamische speicheranforderungen z.b.).



  • Michael E. schrieb:

    Dann hast du wohl wieder im Erbsenzählen gewonnen. Herzlichen Glückwunsch. Da kann keiner mithalten. Klugscheißer.

    naja du hast ja wohl mit erbsenzählen angefangen. die unterscheidung sprache <-> library ist zumindest für mich total klar, und somit auch klar dass std::swap nicht zur sprache gehört.



  • hustbaer schrieb:

    ;fricky schrieb:

    kennt einer eigentlich ein sinnvolles beispiel, bei dem objekte selbst geswappt werden müssen?

    naja z.b. beim sortieren von arrays etc.

    ok, aber swappen innerhalb von arrays ist ja in Java kein problem (^^hab weiter oben ein beispiel gezeigt).

    hustbaer schrieb:

    eigentlich reichts doch immer, wenn man referenzen rumschubst anstatt objektinhalte auszutauschen.

    in C++ arbeitet man wo es geht mit value-semantics, und nicht mit reference-semantics, weil's einfach schneller ist (weil keine/weniger dynamische speicheranforderungen z.b.).

    wieso schneller? umschaufeln der speicherinhalte ganzer objekte kann doch nicht schneller sein, als das umhängen von referenzen.
    🙂



  • Die value-semantics sagt aus wie man dem Assignment-Operator zur interpretieren hat und nicht ob ich nun den Wert oder die Referenz swappe.
    Weil template <class T> void swap(T& x,T& y) kann ich SmartPointer übergeben und Sematisch werden ist das halt ein Referenztausch, oder - versteh ich C++ zu schlecht?



  • Zeus schrieb:

    Weil template <class T> void swap(T& x,T& y) kann ich SmartPointer übergeben und Sematisch werden ist das halt ein Referenztausch, oder - versteh ich C++ zu schlecht?

    ich verstehe von c++ wahrscheinlich viel weniger als du, aber für mich sieht das so aus, als sollen die inhalte von x und y selbst getauscht werden. sind x und y nun ziemlich grosse objekte, dürfte so'n tausch verdammt ungeil sein. sind x und y pointer, wäre es viel schneller. deswegen ja (immer noch) meine frage: wann ist es sinnvoll, objektinhalte selbst zu swappen anstatt referenzen (oder pointer).
    und noch 'ne frage: da man ja nicht einfach rohen speicher rumschaufeln sollte (wie Nexus z.b. erzählt hat), wie funktioniert so'n tausch überhaupt? bei nichttrivialen objekten müssten es doch tiefe kopien werden. sowas macht C++ ja nicht automatisch (Java aber kann das, hähä). müssen die objekte 'swappable' sein, oder wie läuft das?
    🙂



  • ;fricky schrieb:

    müssen die objekte 'swappable' sein, oder wie läuft das?
    🙂

    quasi. Ein Objekt ist swappable, wenn für jeden Member gilt: er ist swappable. Merke: ist ein Objekt kopierbar, ist es swappable. Solange man also nicht mit zeigern rumhantiert ist man automatisch auf der sicheren Seite.



  • ;fricky schrieb:

    sind x und y nun ziemlich grosse objekte, dürfte so'n tausch verdammt ungeil sein.

    Wenn für die Klasse kein swap() bereitstellt, ist das sehr gut möglich. Sobald man aber eine sinnvolle Tauschfunktion einrichtet, wird ein Tausch nicht nur exceptionsicher, sondern sehr performant, wie schon Shade Of Mine erzählt hat. 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, funktioniert aber auch, wenn beide Objekte im automatischen Speicherbereich angelegt wurden.

    Sei doch bitte in Zukunft etwas mehr auf diese Weise interessiert, solche Diskussionen mag ich nämlich. 🙂



  • hustbaer schrieb:

    naja du hast ja wohl mit erbsenzählen angefangen.

    DEvent schrieb:

    Nexus schrieb:

    Das Inline-Schreiben des Tauschs über drei Zuweisungen ist meiner Ansicht nach eher Low-Level als ein swap() -Funktionsaufruf, weil die temporäre Variable ein Implementierungsdetail ist.

    In diesem Punkt abstrahiert C++ sogar besser, da es eine fertige Funktion für sowas anbietet und es dem Aufrufer egal sein kann, auf welche Weise zwei Objekte getauscht werden.

    Die Sprache C++ bietet eine swap-Funktion oder swap-Konstrukt? Das ist mir neu.



  • 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 von std::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 nicht std::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() ) durchgehend std::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


Anmelden zum Antworten