Wann sollte ich C# über C++11 benutzen?



  • DirectX 11 = veraltet schrieb:

    Arbeitest du bei Microsoft?

    Nope



  • Danke für den Fullquote...

    Lightspeed=>C++ schrieb:

    Ich war und bin als unregistrierter Unterwegs und ich habe das deswegen in diesen Thread geschrieben, weil er aus meiner Sicht der einzige ist, der in Frage käme. Denn wie ich bereits sagte, ich weiß nicht warum ich gebannt wurde, aber wenn, dann wegen meinem Beitrag in diesem Thread.

    Da Du zuvor wie derzeit als Unregistrierter unterwegs bist, warst Du also auch nicht gebannt. Wie Dir schon erklärt wurde, hast Du vielleicht eine gebannte IP benutzt - in dem Fall lag es nicht an Dir. Wenn ich das richtig sehe, gibt es kein Problem, also ist die Sache soweit erledigt. Falls doch => PM.

    Nexus schrieb:

    Xin schrieb:

    Ich liebe diese Formulierungen in diesem Forum, die nahezu grundsätzlich davon ausgehen, dass das Gegenüber einen Mangel haben muss...

    War nicht persönlich gemeint, aber ich hatte den Eindruck, dass du mein Beispiel absichtlich falsch verstanden hast. Die Verallgemeinerung von T auf polymorphe Klassen erschien mir nun nicht so wahnsinnig weit hergeholt.

    Ich programmiere bald 20 Jahre in C++, ich komme sicherlich aus einem Umfeld wo auch Assembler und C normal sind daher bin ich sicherlich nicht so empfänglich für shared_ptr. Ich entwickle aber auch selbst eine Programmiersprache und mache mir da genauso meine Gedanken. Da spielen unique und shared Pointer genauso eine wichtige Rolle - und zwar direkt in der Sprache, weil ich die Vorteile durchaus sehe und für so wichtig halte, dass ich damit mit weniger syntaktischen Mehraufwand umgehen möchte als in C++.

    Nochmal... ich schreibe in meinem ersten Posting, dass hier Java Vorteile hat, weil es in C++ einen syntaktischen Mehraufwand gibt und Ringreferenzen durch referenzzählende Shared-Pointer nicht aufgelöst werden können. Bei einer doppelt verketteten Liste gibt es immer mindestens ein Element, dass noch auf ein Node zeigt.
    Du kommst um ein "delete" nicht herum, auch wenn es "remove" heißt, was die SharedPointer auf Null setzt und über diesen dann "delete" ruft. Es ist kein Vorteil, das Wort "delete" in einem Quelltext zu vermeiden und durch ein anderes zu ersetzen. Ein Vorteil entsteht erst, wenn der Compiler Verantwortung übernehmen kann; ein in meinen Augen größerer Vorteil entsteht, wenn der Compiler den Entwickler auf nicht wahrgenommene Verantwortung hinweisen kann, ohne sie ihm abzunehmen: Das hält den Entwickler wachsam und stärkt sein Verständnis von dem, was er da schreibt. Im von mir benannten Listen-Beispiel verschleiert ein Referenzzähler die Verantwortung: Der Entwickler glaubt aus der Alltagserfahrung, sie abgegeben zu haben, muss aber tatsächlich selbst ran. Hier scheitern auch viele GCs (an die Haarspalter: viele heißt nicht alle).

    Hier hat C#/Java Vorteile im Vergleich zur manuellen Speicherverwaltung. Alleine die Tatsache, dass Du std::xxx_ptr schreiben musst ist ein manueller Akt. Du als Entwickler bist verantwortlich, das Richtige zu schreiben, in C#/Java schreibst Du "new bla()" und hast trotzdem kein Speicherleck (wenn man vom immensen Speicherverbrauch des GCs mal absieht)
    Das geht in C++ auch, aber auch da musst Du von Hand ran. Du musst immer die Verantwortung tragen, egal ob Du Dein "delete" in unique_ptr versteckst oder selbst schreibst. Es ist immer Mehraufwand und Verantwortung und nicht nur "Mehraufwand".

    Und dennoch ist C++ besser, denn die Nachteile von C#/Java überwiegen, sobald Dein Projekt eine gewisse Größe erreicht haben, sobald der GC zuviel Leistung oder Speicher abzwackt, sobald Du nicht mehr in der Lage bist, das Projekt vollständig zu überblicken und jede semantische Unterstützung des Compilers zur Fehlervermeidung brauchst, die Du bekommen kannst.

    Memoryleaks sind ein Anfängerproblem. RAII und SmartPointer sind zum Teil gültige Lösungen dafür, aber syntaktisch und im Fall von Shared-Pointern auch Leistungsmäßig Mehraufwand zu einfachen Pointern.

    Nexus schrieb:

    Xin schrieb:

    Nicht alles lässt sich über unique_ptr lösen.

    Und shared_ptr kosten. Wenn man bereit ist die Kosten zu tragen, kein Problem. Aber es gibt eben auch durchaus Fälle, wo man diese Kosten nicht tragen will. Oder wo das ganze einfach keinen Mehrwert ergibt.

    Ja, sehe ich auch so. Aber dann hat man die Speicherverwaltung üblicherweise auf einen oder wenige Orte konzentriert, und nicht über den ganzen Code verteilt. Und oft kann man dabei den entsprechenden Code mit RAII wegkapseln, statt sich bei jeder Anwendung wieder erneut mit new und delete herumzuschlagen.

    Habe ich kein Problem mit.
    Ich weiß nicht, was Du mit 'über den ganzen Code' verteilt meinst, aber wenn das auf Spaghetti-Speicheralloziierung (ähnlich wie das Rumhüpfen mit Goto) rausläuft, bin ich voll bei Dir.
    In der Regel gibt aber das Problem mir vor, wo ich new und delete brauche.
    Ich löse Probleme, bevorzugt auf die einfachste Art, die mir zur Verfügung steht. Ich bin kein Verfechter von akademischen Weisheiten. Alles hat seinen Wert und alles hat seine Ausnahme.

    Die Frage ist, ob man einen guten Grund hat, warum man etwas so oder so entwickelt, die üblichen Lehrmeinungen gelten nur für die Mehrheit der Fälle, aber nicht für die Allgemeinheit.

    Nexus schrieb:

    Xin schrieb:

    Deswegen bringe ich es auch ganz locker über die Lippen, dass ich manche Probleme ohne std::Problemloesung löse und dann gerne new und delete verwende.

    Ich sage nicht, man solle immer Standardlösungen verwenden -- aber wenn du deine spezifischen Container schreibst, die Objekte nicht direkt initialisieren, kannst du Low-Level-Operationen wie Speicherverwaltung doch intern abhandeln.

    Mache ich auch, dafür sind die Container ja da.

    Ein spezialisierter Container ist Teil eines speziellen Programms und der muss auch geschrieben werden. Es gibt aber innerhalb des Containers kein Intern. Da muss man mit new und Placement-New und delete oder dem direkten Aufruf des Destructors, um Objekte zu zerstören, für die man gar keinen Speicher alloziiert hat.

    Und wenn dann Leute ankommen, die über hunderte Klassen nur drei delete brauchen oder feststellen, dass RAII immer besser ist, dann kann ich nur sagen, dass diese Leute offenbar andere Probleme zu lösen haben als ich.
    Und wer "immer" schreibt muss andere Erfahrungen gemacht haben als ich.

    Wäre schön, wenn diese Personen dann in Erwägung ziehen könnten, dass ich deswegen nicht zwangsläufig auf dem falschen Dampfer bin, sondern einfach andere Probleme löse. Eventuell sogar sinnvoll.

    Nexus schrieb:

    Xin schrieb:

    Liebelein, Du hast recht und ich meine Ruhe.

    Sorry, aber ein viel sinnloseres "Argument" als "es funktioniert ja" gibts echt nicht.

    Och, ich halte "Es funktioniert" für ein sehr gutes Argument.

    Fast alle Entwickler sind schlauer als andere. Aber nicht davon alle schreiben funktionierende Software. Ich muss hier häufiger mal ziemlich haarige Fehler debuggen und zumindest letztes Jahr war kein Fehler von mir dabei.

    Ansonsten ich mich auch nicht genötigt, hier irgendwem Rechenschaft abzulegen. Ich unterhalte mich gerne über unterschiedliche Erfahrungen, aber sobald mir jemand sagt, der meine Probleme und meinen Background nicht kennt, dass mir die Vorstellungskraft fehlt oder mir Regeln mit "immer" erklärt, sinkt auch meine Bereitschaft, irgendetwas zu begründen. Wenn's vorher nicht interessierte, interessiert nun auch keinen.

    Hier kann man drüber reden, weshalb ich welche Meinung vertrete, aber ich sehe keinen Grund in jeder zweiten Diskussion erklärt zu bekommen, dass ich Dinge falsch mache und dann auf dem Standpunkt zu stehen, dass ich mich verteidigen müsste. Wen's interessiert hätte, hätte wohl gefragt, statt einen Schlagabtausch zu initiieren.

    "Es funktioniert" muss dann reichen. Dass meine Software funktioniert weiß ich schon und dass ich zumindest gut genug bin um für meine Programmierkenntnisse akzeptabel bezahlt zu werden, weiß ich auch. Hier um Recht zu kämpfen hingegen oder dafür zu sorgen, dass jemand eine sinnvolle Antwort lesen kann, nachdem er sowieso überzeugt ist, dass ich keine Ahnung habe, macht weder meine Software funktionstüchtiger, noch erhöht es meinen Kontostand.

    Eine freundlich formulierte Frage, die Interesse zeigt und die Chance auf eine für beide Seiten inspirierende Diskussion birgt, hat da für mich einen viel höheren Reiz. Das bietet die Chance, meine Software zu verbessern.



  • Okay, dann sind wir uns ja grösstenteils doch einig.

    Wie gesagt, das mit der Vorstellungskraft habe ich geschrieben, weil du meine Aussage mit der polymorphen Basisklasse wörtlich genommen hast, statt sie sinnvoll zu interpretieren.

    "Es funktioniert" ist schon deswegen kein Argument in unserer Diskussion über Programmiertechniken, weil die Beobachtung der Semantik alleine nichts über Codequalität aussagt. Neben einem funktionierenden Resultat ist nämlich auch Entwicklungszeit relevant -- daher zahlen sich Techniken aus, welche die Umsetzung eines Features in kürzerer Zeit, mit weniger Wartungs- und Debugaufwand ermöglichen.



  • dot:
    Stört Dich bei QT die Compilezeit wegen dem moc oder wo genau kommst Du so sehr mit der "Ästhetik" in Berührung, dass Dich das traurig stimmt?

    Ich habe auch Mal überlegt C# für UI zu verwenden, aber ich kriege mit QT alles hin (teilweise nach etwas Suche, wie man Probleme löst, gut).



  • Ich finde C# sehr elegant, unproduktiver als C++ gefühlsmäßig nicht.

    Ein GC ist in der Verwendung doch deutlich angenehmer als Smartpointer ... ich habe mal tief unten in einer Hierachie, in der viele Objekte andere Objekte besitzen einen vector<unique_ptr<Foo>> verwendet ... GCC hat ein paar Seiten Fehler ausgespuckt und ich habe recht lange gebraucht bis ich die Stelle gefunden habe, an der ein Unterobjekt nicht gemoved sindern kopiert wurde. Die Fehlermeldungen haben 0 geholfen.

    Klar ist das toll so den Fehler zu finden, aber ich persönlich opfere lieber ein paar Mikrosekunden Laufzeit als ewig auf Fehlersuche zu gehen. 😉
    War schon auf dem Sprung einfach shared_ptr zu verwenden damit ich meine Ruhe habe, hab mich aber doch durchgebissen.



  • "Es funktioniert" muss dann reichen.

    Meine Qualitaetsansprueche sind hoeher.

    Das bietet die Chance, meine Software zu verbessern.

    Dann probiere es doch einfach aus, verzichte auf new.

    paar Mikrosekunden Laufzeit als ewig auf Fehlersuche zu gehen

    Mein Kompiler sagt mir die Zeilennummer, der Rest ist Uebungssache. D.h. Fehler von Templates sind ebenfalls schnell behoben.



  • Eisflamme schrieb:

    Stört Dich bei QT die Compilezeit wegen dem moc oder wo genau kommst Du so sehr mit der "Ästhetik" in Berührung, dass Dich das traurig stimmt?

    Mich stört allein schon die Existenz von moc und z.B. dass Qt nicht die nativen Steuerelemente verwendet, sondern diese nur emuliert...



  • @Xin Kannst du eine Situation konstruieren in der du 1. delete brauchst und 2. nicht gerade einen Container schreibst?



  • cooky451 schrieb:

    @Xin Kannst du eine Situation konstruieren in der du 1. delete brauchst und 2. nicht gerade einen Container schreibst?

    Wer delete wirklich brauchen würde, könnte smart pointers nehmen, oder?
    Die könnte man auch in Containern, also sagen wir doch erstmal, daß man niemals delete braucht.



  • Ich finde in dieser Diskussion von wegen new und delete geht die eine wesentliche Erkenntnis leider unter, nämlich: Ressourcenverwaltung ist in C++ ein gelöstes Problem.



  • @volkard Smartpointer sind für mich auch nur Container. 😉

    dot schrieb:

    Ich finde in dieser Diskussion von wegen new und delete geht die eine wesentliche Erkenntnis leider unter, nämlich: Ressourcenverwaltung ist in C++ ein gelöstes Problem.

    Ja, aber dann kam

    Xin schrieb:

    Das fängt den Mehraufwand durch die manuelle Speicherverwaltung deutlich auf.

    Und alle so: Wowowowowow Alter, was'n das? 😃



  • cooky451 schrieb:

    @Xin Kannst du eine Situation konstruieren in der du 1. delete brauchst und 2. nicht gerade einen Container schreibst?

    Die Frage an sich ist schon fragwürdig gestellt, denn sie impliziert 1. dass es mit einem Smartpointer nicht gehen darf. Die Frage ist für mich nicht, ob ich es nicht auch mit einem SmartPtr lösen könnte, sondern ob ich überhaupt einen SmartPointer wünsche.
    Und 2. hast Du schon ein Beispiel ausgeschlossen: Ein Gegenbeispiel reicht oder glaubst Du ich spring hier jetzt, bis Du eine Liste hast und keinen Bock weitere Wünsche zu äußern?

    Schon alleine deswegen

    cooky451 schrieb:

    Xin schrieb:

    Das fängt den Mehraufwand durch die manuelle Speicherverwaltung deutlich auf.

    Und alle so: Wowowowowow Alter, was'n das? 😃

    Wowowowowow... Stinkefinger.

    Die Diskussion ging ursprünglich um C# oder C++. Dem "Wowowow"-Poserstyle brauche ich wohl nicht beizuwohnen.

    volkard schrieb:

    cooky451 schrieb:

    @Xin Kannst du eine Situation konstruieren in der du 1. delete brauchst und 2. nicht gerade einen Container schreibst?

    Wer delete wirklich brauchen würde, könnte smart pointers nehmen, oder?
    Die könnte man auch in Containern, also sagen wir doch erstmal, daß man niemals delete braucht.

    Ein SmartPointer ist ein Container für Pointer. "NIEMALS" braucht man delete...

    Wer unbedingt SmartPointer nutzen will und das für etwas weltbewegendes hält, dass alle seine Probleme löst, wunderbar.

    Wer das für die einzige Wahrheit hält, "Du sollst keine Pointer neben dem Smartpointer anbeten", dann haben wir was Religiöses. Und mit religiösen Fanatikern verschwendet man höchstens Zeit.

    Nochmals: Ich spreche mich nicht gegen SmartPointer aus, also packt euren Scheiterhaufen wieder ein. Aber da eh keiner liest, was schon geschrieben wurde...



  • Meine Behauptungen sind nur:
    - Man braucht delete nur in Containern. (Einschließlich Smartpointern.)
    - Container schreibt man (fast) nie, insbesondere wenn einem die Standardbibliothek zur Verfügung steht.
    => Ich sehe keinen Mehraufwand in der Speicherverwaltung. (unique_ptr tippen zu müssen zählt nicht für mich, da kann ich mich genau so über die ganzen Namespaces beschweren.)



  • Ich finde diese Diskussion durchaus erfrischend. Und das Resümee für mich ist mal wieder das, was ich an C++ so schätze: Ich habe die Wahl. Wenn ich den Speicher manuell verwalten möchte oder einen triftigen Grund dafür habe, dann kann ich es tun. Wenn ich es automatisch tun möchte, dann gibt es Werkzeuge bis hin zu GC. Und dazwischen alles, was das Herz begehrt.

    Es gibt einfach in C++ keine Grenzen. In fast jeder anderen Sprache gibt es die eine oder andere Einschränkung. Und sei es, dass ein GC die Objekte wegräumt auch wenn es für den Anwendungsfall nicht sinnvoll erscheint.

    Die vielen Möglichkeiten implizieren natürlich die Notwendigkeit, verantwortungsvoll mit diesen umzugehen und natürlich auch relativ viel Know how. ich brauche den Unterschied zwischen Stack- und Heapobjekten nicht zu kennen, wenn meine Sprache das nicht unterstützt.

    Ich persönlich bevorzuge die Freiheit von C++. Und wenn die Freiheit impliziert, dass ich ungebremst gegen die Wand fahren kann wenn ich will, dann ist das OK.



  • tntnet schrieb:

    ich brauche den Unterschied zwischen Stack- und Heapobjekten nicht zu kennen, wenn meine Sprache das nicht unterstützt.

    Nur um hier mal völlig unpassend einen kleinen Java-Seitenhieb zu plazieren: Irgendwie schon. Java kennt ja Stack-Variablen, man kann sich nur nicht aussuchen wo man was haben will. 😃 Aber dieses Verhalten muss auch einem Java-Anfänger klar sein:

    static void foo(MyObject o, double d)
    {
      o.foo(); // Verändert möglicherweise das worauf o zeigt
      d = 66.6; // Verändert nur die lokale Kopie
    }
    


  • cooky451 schrieb:

    tntnet schrieb:

    ich brauche den Unterschied zwischen Stack- und Heapobjekten nicht zu kennen, wenn meine Sprache das nicht unterstützt.

    Nur um hier mal völlig unpassend einen kleinen Java-Seitenhieb zu plazieren: Irgendwie schon. Java kennt ja Stack-Variablen, man kann sich nur nicht aussuchen wo man was haben will. 😃 Aber dieses Verhalten muss auch einem Java-Anfänger klar sein:

    static void foo(MyObject o, double d)
    {
      o.foo(); // Verändert möglicherweise das worauf o zeigt
      d = 66.6; // Verändert nur die lokale Kopie
    }
    

    Ja aber das hat absolut nichts mit tntnets Aussage zu tun.



  • Xin schrieb:

    Nochmal... ich schreibe in meinem ersten Posting, dass hier Java Vorteile hat, weil es in C++ einen syntaktischen Mehraufwand gibt und Ringreferenzen durch referenzzählende Shared-Pointer nicht aufgelöst werden können. Bei einer doppelt verketteten Liste gibt es immer mindestens ein Element, dass noch auf ein Node zeigt.

    Abgesehen davon, dass shared Ownership eine meiner Erfahrung nach extrem seltene Angelegenheit und referenzzählende Smartpointer daher ein sehr seltener Anblick sind, wäre das eigentliche Problem hier imo nicht, dass Referenzzählung eine Ringreferenz nicht auflösen kann, sondern die Tatsache, dass du überhaupt eine Ringreferenz hast. Dass zwei Objekte sich gegenseitig besitzen, macht rein prinzipiell keinen Sinn. Alle Links in einer doppelt verketteten Liste über shared_ptr oder etwas vergleichbares zu implementieren, ist imo einfach nur falsch (es steht im logischen Widerspruch zum Konzept einer Liste) und die daraus resultierenden Probleme sind als Folge der Missachtung von Naturgesetzen zu verstehen. Wenn du in einem Taucheranzug aus einem Flugzeug springst, ist imo jedenfalls nicht der Taucheranzug verantwortlich dafür, dass die Folgen der Gravitation potentiell unangenehm sind...

    Xin schrieb:

    Es ist kein Vorteil, das Wort "delete" in einem Quelltext zu vermeiden und durch ein anderes zu ersetzen.

    Wir ersetzen aber nicht einfach nur das Wort "delete" im Quelltext durch etwas anderes, sondern führen ein Konzept ein, welches die Formulierung einer Lösung vereinfacht.

    Xin schrieb:

    Ein Vorteil entsteht erst, wenn der Compiler Verantwortung übernehmen kann; ein in meinen Augen größerer Vorteil entsteht, wenn der Compiler den Entwickler auf nicht wahrgenommene Verantwortung hinweisen kann, ohne sie ihm abzunehmen: Das hält den Entwickler wachsam und stärkt sein Verständnis von dem, was er da schreibt. Im von mir benannten Listen-Beispiel verschleiert ein Referenzzähler die Verantwortung: Der Entwickler glaubt aus der Alltagserfahrung, sie abgegeben zu haben, muss aber tatsächlich selbst ran. Hier scheitern auch viele GCs (an die Haarspalter: viele heißt nicht alle).

    Hier hat C#/Java Vorteile im Vergleich zur manuellen Speicherverwaltung. Alleine die Tatsache, dass Du std::xxx_ptr schreiben musst ist ein manueller Akt. Du als Entwickler bist verantwortlich, das Richtige zu schreiben, in C#/Java schreibst Du "new bla()" und hast trotzdem kein Speicherleck (wenn man vom immensen Speicherverbrauch des GCs mal absieht)
    Das geht in C++ auch, aber auch da musst Du von Hand ran. Du musst immer die Verantwortung tragen, egal ob Du Dein "delete" in unique_ptr versteckst oder selbst schreibst. Es ist immer Mehraufwand und Verantwortung und nicht nur "Mehraufwand".

    Daraus werd ich irgendwie nicht schlau. Erst argumentierst du, wie wichtig es doch ist, dass eine Sprache dem Programmierer nicht die Möglichkeit gibt, "Verantwortung abzugeben" und im nächsten Absatz sagst du dann, dass Java und C# gegenüber C++ den Vorteil haben, dass der Programmierer in diesen Sprachen keine Verantwortung übernehmen muss!?

    Xin schrieb:

    Memoryleaks sind ein Anfängerproblem. RAII und SmartPointer sind zum Teil gültige Lösungen dafür, aber syntaktisch und im Fall von Shared-Pointern auch Leistungsmäßig Mehraufwand zu einfachen Pointern.

    Inwiefern sind shared_ptr deiner Meinung nach leistungsmäßiger Mehraufwand im Vergleich zu einfachen Pointern (ich vermute mal, du hast einfach übersehen, dass du da Äpfel und Bäume vergleichst)? Überhaupt: Kann es sein, dass du den Eindruck hast, dass hier gepredigt wird, dass alle Pointer durch shared_ptr ersetzt werden sollen? Falls ja: Das ist nicht der Fall, wer sowas behauptet, kann Smartpointer nicht verstanden haben. Bei RAII geht es um das Management von Ressourcen und nicht darum, das Konzept "Pointer" durch etwas anderes zu ersetzen. Smartpointer und Pointer haben eigentlich überhaupt nichts miteinander zu tun, die Bezeichnung "Smartpointer" ist (historisch bedingt) wohl leider etwas unglücklich gewählt. Wir sollten in Zukunft wohl besser einfach nur von "RAII Guards" oder so reden, um derartige Missverständnisse auszuschließen...



  • Gibt's eigentlich schon nen Compiler, der versucht einen GC für C++ zu implementieren? Seit C++11 ist es ja theoretisch möglich.



  • Wie genau meinst du das? C++ Pointer kann man generell nicht GCen denke ich. Ich meine, die kann man in eine Datei schreiben und wieder auslesen theoretisch, da muss man schon striktere Regeln in den Standard schreiben. 😃 Ansonsten: VS dürfte gcnew haben.



  • Zu irgendetwas müssen doch die Einführung einer GC-ABI in den Standard und Krams wie std::declare_reachable gut sein. 😉


Anmelden zum Antworten