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



  • Ich programmiere jetzt seit ca 2 Jahren. Angefangen habe ich mit Java -> C# -> Python -> Scala -> c++11

    Ich war immer der Meinung das man mit C# viel produktiver ist als mit C++. Doch vor 2 Monaten habe ich angefangen C++11 zu lernen und es ist ganz anders als ich es mir vorgestellt habe.

    Manual memory management mit smart pointern ist nicht wirklich mehr Aufwand als automated memory management.
    Vielleicht gibt es Bereiche in denen eine GC nützlicher ist?

    Zu meiner eigentlichen Frage:

    Wann sollte ich C# über C++ benutzen? In welchen Bereichen hat C# seine stärken? (Gegenüber c++)



  • Naja, in C# und Java ist man schon schneller fertig als mit C++.
    Das ist einfach so, weil man bei C++ wesentlich mehr beachten muss.

    Zu deiner Frage:

    C# solltest du vorziehen wenn:
    1. es schnell gehen soll
    2. die Akzeptanz der SW beim Kunden nicht so wichtig ist. (ich bevorzuge z.B: C++ Anwendungen, weil die nicht erst noch nen fettes .Net zum Starten laden müssen)
    3. du dein Problem auch in C# realisieren kannst. Treiber und die Ansteuerung von HW, sowie alle Gebiete der Systemprogrammierung machst du besser in C++.
    4. Wenn Performance nicht so wichtig ist.
    5. Wenn es dir egal ist, dass die Anwendung nur für Windows entwickelt wird. (es gibt zwar Mono für Linux, aber C# Anwendungen sind auf den ganzen anderen Plattformen immer ein großer Fremdkörper)



  • Gründe könnten sein:
    - Es gibt eine bestimme Bibliothek die über 50% der Arbeit bereits für dich erledigt nur für C#. (Ist alleine schon bei .NET nicht unbedingt selten. ;))
    - Du willst schnell ein Mini-Programm mit GUI für Windows zusammen-frickeln. Das geht in C# einfach schneller.

    Ansonsten, sprachlich gesehen, sehe ich sowohl C# als auch Java (Java noch deutlich mehr) C++11 eigentlich als deutlich unterlegen an. Keine Ahnung warum da immer von "man ist ja so viel produktiver" geredet wird, ich finde C++ nimmt mir in jeglicher Hinsicht mehr Arbeit ab. (Sprachlich gesehen. Dass die Standardbibliothek viel zu klein ist, darüber brauchen wir uns nicht unterhalten denke ich.)

    Vielleicht gibt es Bereiche in denen eine GC nützlicher ist?

    Ja, gibt es. Wenn du lock-free data structures selbst programmieren musst. Aber das ist schon eine recht spezielle Anwendung - und es ist ja nicht so, dass es nur damit funktionieren würde. Es ist nur leichter. Nur, üblicherweise programmiert man sich so etwas eh nicht selbst und wenn doch, sollte man wohl so oder so ein gutes Stück Gehirnschmalz rein stecken. 😉



  • Noch mal zur Produktivität.
    Ich verbringe viel mehr Zeit ein Programm zu designen als es zu implementieren.
    Vielleicht geht das mit der Zeit schneller aber momentan würde ich sagen ~ 70% designen 30% implementieren.

    Ist das bei anderen Programmieren auch so?



  • Kommt darauf an: Bei privaten Projekten ist es eher so, dass ich entweder fast nur plane (90%) (z.B. wenn ich eine Art lib machen will, eben bei größeren Dingen), oder fast nur implementiere (90%) eben wenn ich irgendein kleines Tool haben will, das mir eine Aufgabe abnimmt. Aufträge sind dann genau dazwischen, da liegt die Verteilung dann zwischen 40% und 60%, je nach Aufgabe. Wobei die Aufträge normalerweise auch nicht länger als 100 Stunden dauern, sonst würde ich wohl mehr planen, dann fängt es an sich zu lohnen.



  • Wenn du Wert auf Hohe Langsamkeit legst, solltest du C# präferieren.



  • low_fastness schrieb:

    Wenn du Wert auf Hohe Langsamkeit legst, solltest du C# präferieren.

    Mit anderen Worten, wenn man dabei zusehen will, wie die CPU die Bits in die Register schiebt, dann sollte man C# nehmen.

    Bei C++ geht das leider so schnell, das man nix mehr sieht.



  • kantaki schrieb:

    Ich programmiere jetzt seit ca 2 Jahren. Angefangen habe ich mit Java -> C# -> Python -> Scala -> c++11

    Ich war immer der Meinung das man mit C# viel produktiver ist als mit C++. Doch vor 2 Monaten habe ich angefangen C++11 zu lernen und es ist ganz anders als ich es mir vorgestellt habe.

    Nach zwei Jahren in C++ Vorteile zu entdecken halte ich schon für recht gut. Das dauert üblicherweise länger.

    kantaki schrieb:

    Manual memory management mit smart pointern ist nicht wirklich mehr Aufwand als automated memory management.
    Vielleicht gibt es Bereiche in denen eine GC nützlicher ist?

    Ich finde den Aufwand teilweise deutlich größer als in C#/Java. Den GC braucht man allerdings nicht, um qualitative Software zu schreiben.

    Aktuell programmiere ich in Python, wo ich anfangs extrem produktiv startete, aber die Sprache semantisch schnell zurück bleibt. Sie erlaubt mir also Fehler zu machen, ohne dass ich das mitbekomme. Das Problem gibt es auch in Java und C# - auch in C++ natürlich, aber C++ liefert da einiges mehr als die vorgenannten. Das fängt den Mehraufwand durch die manuelle Speicherverwaltung deutlich auf.
    Dafür muss man allerdings mehr lernen. Für kleine Hobbyprojekte reicht Java und C# wunderbar.
    Für alles was mehr ist... würde ich davon abraten.

    kantaki schrieb:

    Zu meiner eigentlichen Frage:

    Wann sollte ich C# über C++ benutzen? In welchen Bereichen hat C# seine stärken? (Gegenüber c++)

    Die mitgelieferten Frameworks muss man nicht nachträglich installieren, sondern man kann sie direkt nutzen.
    Wenn Du eine billige GUI brauchst, bietet sich WinForms an.

    Ich sehe C# als eine Art Skriptsprache zwischen den bekannten Skriptsprachen und C++. Es ist eine gute und durchaus schnelle Sprache. Aber wenn man's richtig machen will, wenn man mehr machen will als Algorithmen, die Fließband-Aufgaben erledigen, dann bin ich schnell bei C++. Wenn ich ein Projekt in einer Größe aufbaue, dass ich es nicht alleine überblicken kann, dann brauche ich C++ und die Features, die man in C# zur Vereinfachung weggelassen hat.

    Ein GC braucht eigentlich kein Mensch. Im Schnitt meldet valgrind alle 3-6 Monate mal ein Leak, welches ich mir was angucken sollte. Dann mache ich das und dann war's das.



  • Xin schrieb:

    Ein GC braucht eigentlich kein Mensch. Im Schnitt meldet valgrind alle 3-6 Monate mal ein Leak, welches ich mir was angucken sollte. Dann mache ich das und dann war's das.

    Man brauchts nicht, weil men es als C++ Programmierer eben gewohnt ist, seinen Code ohne GC zu programmieren.
    Der unberechtigten Ban war übrigens fehl am Platz.



  • Bei C++ brauchst du halt sehr lange, bis du die Sprache wirklich effizient einsetzen kannst. D.h. du kennst nicht nur die Sprachmittel, sondern auch Idiome und kannst die verschiedenen Abstraktionsmöglichkeiten kombinieren. Ich würde mal behaupten, der durchschnittliche C++-Programmierer ist nicht so weit. Typischer C++-Code ist daher tendenziell eher kompliziert und erweckt den Eindruck, man müsse viele Low-Level-Arbeiten selbst erledigen.

    Wenn du C++ jedoch gut beherrschst, hast du in mächtiges Werkzeug zur Hand, mit dem du in kurzer Zeit viel erreichen kannst.

    Xin schrieb:

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

    Was für einen Mehraufwand? Wenn du in C++ manuell Speicher verwaltest, hast du was Grundsätzliches nicht verstanden.



  • Lightspeed=>C++ schrieb:

    Xin schrieb:

    Ein GC braucht eigentlich kein Mensch. Im Schnitt meldet valgrind alle 3-6 Monate mal ein Leak, welches ich mir was angucken sollte. Dann mache ich das und dann war's das.

    Man brauchts nicht, weil men es als C++ Programmierer eben gewohnt ist, seinen Code ohne GC zu programmieren.

    Damit meine ich nicht die Gewohnheit, sondern die Notwendigkeit.
    Geschätzt 90% bei der Speicherveraltung lassen sich mit C++ besser lösen als mit Java/C# und dem GC. Beim Rest muss man sich wirklich fragen, ob man dafür so ein Ungetüm haben will.
    Ich bin der Meinung, dass das kein Mensch braucht.

    Lightspeed=>C++ schrieb:

    Der unberechtigten Ban war übrigens fehl am Platz.

    Ban? Worum geht's und müsste ich was davon wissen?

    Nexus schrieb:

    Xin schrieb:

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

    Was für einen Mehraufwand? Wenn du in C++ manuell Speicher verwaltest, hast du was Grundsätzliches nicht verstanden.

    Tja, dann habe ich wohl was Grundsätzliches nicht verstanden.
    Ich löse in erster Linie Probleme mit C++ und da gehören auch teilweise manuelle Speicherorganisation dazu. Kann aber auch sein, dass ich andere Probleme als Du löse.



  • Xin schrieb:

    Ich löse in erster Linie Probleme mit C++ und da gehören auch teilweise manuelle Speicherorganisation dazu. Kann aber auch sein, dass ich andere Probleme als Du löse.

    Ein Beispiel?



  • volkard schrieb:

    Xin schrieb:

    Ich löse in erster Linie Probleme mit C++ und da gehören auch teilweise manuelle Speicherorganisation dazu. Kann aber auch sein, dass ich andere Probleme als Du löse.

    Ein Beispiel?

    ...entweder verstehe ich hier gerade "manuelle Speicherorganisation" nicht, aber ich brauche wohl kaum ein Beispiel für new und delete zu geben!?

    Ansonsten habe ich durchaus auch Container, die als MemoryPools dienen und über Placement-New Objekte konstruieren.

    SmartPointer sind kein GC, zumal sie nicht in der Sprache verankert sind, ergo die Datentypen aufwendiger zu repräsentieren sind, ergo der Code unleserlicher wird. => Mehraufwand.



  • Ich persönlich verwend C# wenn ich schnell irgendein Tool mit UI basteln möchte, da sowas mit C# tatsächlich sehr einfach und schnell geht. Die Erfahrung lehrt mich allerdings, meine Anwendungen so zu bauen, dass die eigentliche Funktionalität in Form einer C++ Library implementiert wird und das C# UI lediglich eine dünne Schicht oben drüber ist, die einfach die richtigen Knöpfe auf der Library drückt. Ich find C# ist eine sehr praktische Sprache, aber für Dinge wie die einigermaßen effiziente Implementierung komplexer Datenstrukturen oder gar Ressourcenverwaltung leider eher ungeeignet. Und wesentlicher Grund dafür ist unter anderem genau die Garbage Collection, welche imo der fundamentale Schwachpunkt von Sprachen wie C# und Java ist, da Garbage Collection den Umgang mit Ressourcen ohne zu leaken einfach nur unvorstellbar schwer macht. Ja, man muss sich nicht mehr darum kümmern, dass jedes new sein passendes delete hat. Aber der Preis den man dafür zahlt, nämlich dass die Verwaltung jeder anderen Art von Ressource (selbst von so trivialen und allgegenwärtigen Dingen wie Dateien) zur Sisyphusarbeit wird, ist imo nicht zu rechtfertigen. Garbage Collection ist imo gut gemeint, geht das Problem aber vom völlig falschen Standpunkt aus an. Ich finde aber die Kombination von C# und C++ sehr mächtig, was allerdings vor allem daran liegt, dass es leider kein brauchbares UI Toolkit für C++ gibt, wobei es mit Windows 8 da imo einen schwachen Schimmer der Hoffnung am Horizont gibt. Der große Vorteil von C# gegenüber C++ ist die einfach nur riesige Library, die einem mit dem .NET Framework zur Verfügung steht. Rein sprachlich hat C# den Vorteil, dass es vergleichsweise einfach ist, was es zu meiner üblichen Empfehlung für Anfänger macht, hat aber eben auch fundamentale Schwächen, die den potentiellen Nutzen der Sprache am Ende imo leider stark einschränken.

    Zusammenfassung: Wenn es etwas vergleichbares wie das .NET Framework für C++ gäbe, würde ich keinen Gedanken an C# verschwenden. Leider gibt es sowas im Moment aber nicht und das nächstbeste ist die Kombination von C# und C++...



  • Xin schrieb:

    ...entweder verstehe ich hier gerade "manuelle Speicherorganisation" nicht, aber ich brauche wohl kaum ein Beispiel für new und delete zu geben!?

    Doch, und zwar eines das man nicht trivial mit einem STL-Container lösen kann, dessen weglasen dir bei der nächsten Gelegenheit in den Fuß schießt.



  • @Dot: ich weiß nicht, wo du da jetzt Probleme siehst. Ich hab mehrere Jahre als C# Entwickler gearbeitet und wir haben tatsächlich auch einigermaßen größere Programme damit entwickelt und hatten keine Probleme. Weder mit der Performance, der Effizienz noch sonst was. Auch Resourcenverwaltung ist kein Problem.
    Man darf gern C++ mögen und damit arbeiten, aber ich finds etwas unfair und weltfremd, wenn man anfängt zu argumentieren, es wäre schwer oder unmöglich in C# effizient mit Ressourcen zu arbeiten, oder der GC würde stören oder ähnliches. Zu 99,999% merkst du davon absolut rein gar nichts und brauchst dir darum überhaupt keine Gedanken zu machen. Und in C# using zu benutzen ist nicht wirklich umständlicher als in C++ einen smart pointer zu benutzen.



  • otze schrieb:

    Xin schrieb:

    ...entweder verstehe ich hier gerade "manuelle Speicherorganisation" nicht, aber ich brauche wohl kaum ein Beispiel für new und delete zu geben!?

    Doch, und zwar eines das man nicht trivial mit einem STL-Container lösen kann, dessen weglasen dir bei der nächsten Gelegenheit in den Fuß schießt.

    Ich habe mal kurz überlegt, ob ich hierauf noch antworten will.

    Eigentlich nicht, aber ich denke, Du darfst Dir durchaus bewusst werden, dass "Doch" schonmal unpassend ist: Ich brauche nicht und zum anderen habe ich bereits.
    Wenn Du für new und delete keine Verwendung hast, dann herzlichen Glückwunsch, dann solltest Du Dich nicht mit Anfängern wie mir abgeben, sondern Herrn Stroustrup mal eine Mail schreiben, dass er diese Operatoren entfernen möge.

    Ich bin immer wieder erstaunt, wieviele Leute sich hier Sorgen um meine Füße machen. Sorgt euch nicht, ich programmiere schon ein, zwei Jahre und meinen Füssen geht es wunderbar.



  • Ich sehe IDisposable als Symptom und using als Symptombehandlung und nicht als tatsächliche Problemlösung. using ist am Ende nur Syntaxzucker für genau einen konkreten Anwendungsfall, nämlich den einer temporären Ressource in einer Funktion. Zugegeben: Für den Fall funktioniert es. Aber leider deckt das eben auch nur einen Bruchteil des Problems ab. IDisposable ist genau das, was man sich mit Garbage Collection einhandelt. Das Grundproblem mit IDisposable ist, dass es ansteckend ist. Sobald du irgendwo in einer Objekthierarchie ein IDisposable einbaust, musst du sämtliche Objekte weiter oben ebenfalls IDisposable machen. Mit anderen Worten: Du hast mit einem Schlag einen riesen Haufen Code der sich plötzlich um das Management der Lebensdauer eines einzigen Members einer einzigen Klasse irgendwo ganz weit unten kümmern muss. Etwas, das eigentlich als Implementierungsdetail in einer Klasse gekapselt sein sollte, muss plötzlich in Code, der eigentlich nichts damit zu tun haben sollte, berücksichtigt werden. Und auf dieses Problem stoßt man leider sehr schnell. Schonmal eine Klasse geschrieben, die z.B. eine Datei als Member haben sollte, die so lange offen sein soll, wie das Objekt benutzt wird? In C++ geht das völlig natürlich ohne dass ich auch nur irgendwas dafür tun müsste. In C# muss ich dafür nicht nur extra Code schreiben, sondern potentiell auch noch über das ganze Programm verteilt sehr viel dem eigentlichen Problem völlig fremden Code seiner Lesbarkeit berauben...



  • Xin schrieb:

    ...entweder verstehe ich hier gerade "manuelle Speicherorganisation" nicht, aber ich brauche wohl kaum ein Beispiel für new und delete zu geben!?

    Das Problem ist: new und delete gehören nicht in den Anwendercode. Sie sind sinnvoll, da du mit ihnen eine einfache Möglichkeit zur Speicherverwaltung hast, aber ihre Verwendung gehört immer abgekapselt.

    Xin schrieb:

    SmartPointer sind kein GC, zumal sie nicht in der Sprache verankert sind, ergo die Datentypen aufwendiger zu repräsentieren sind, ergo der Code unleserlicher wird. => Mehraufwand.

    Ne. Der Mehraufwand ist bedeutungslos, wenn man beachtet, wie viel Logikcode durch RAII wegfällt. Du hast nachher kein einziges delete mehr. Funktionen mit mehreren Rückgabepfaden oder Exceptions sind automatisch sicher und werden nicht mit Aufräumcode unleserlich gemacht.

    Simples Beispiel:

    // RAII
    std::unique_ptr<T> ptr(new T);
    ptr->func();
    if (ptr->ok())
        return ptr->thing();
    else
        return 47;
    
    // Manuelle Speicherverwaltung
    T* ptr(new T);
    ptr->func(); // func() darf nicht werfen
    if (ptr->ok()) // ok() darf nicht werfen
    {
        int r = ptr->thing(); // thing() darf nicht werfen
        delete ptr;
        return r;
    }
    else
    {
        delete ptr;
        return 47;
    }
    

    Nun stell dir das Gleiche vor mit mehr als einer Ressource. Oder, falls die einzelnen Funktionsaufrufe Exceptions werfen können. Der Code wird wahnsinnig unübersichtlich mit manueller Speicherverwaltung.

    Nene, RAII ist immer besser. Und Smart-Pointer nicht zu benutzen wegen syntaktischem "Mehraufwand" ist doch etwas sehr fragwürdig. Gerade wenn sie Null Laufzeitkosten haben.



  • dot schrieb:

    Sobald du irgendwo in einer Objekthierarchie ein IDisposable einbaust, musst du sämtliche Objekte weiter oben ebenfalls IDisposable machen. Mit anderen Worten: Du hast mit einem Schlag einen riesen Haufen Code der sich plötzlich um das Management der Lebensdauer eines einzigen Members einer einzigen Klasse irgendwo ganz weit unten kümmern muss. Etwas, das eigentlich als Implementierungsdetail in einer Klasse gekapselt sein sollte, muss plötzlich in Code, der eigentlich nichts damit zu tun haben sollte, berücksichtigt werden. Und auf dieses Problem stoßt man leider sehr schnell. Schonmal eine Klasse geschrieben, die z.B. eine Datei als Member haben sollte, die so lange offen sein soll, wie das Objekt benutzt wird? In C++ geht das völlig natürlich ohne dass ich auch nur irgendwas dafür tun müsste. In C# muss ich dafür nicht nur extra Code schreiben, sondern potentiell auch noch über das ganze Programm verteilt sehr viel dem eigentlichen Problem völlig fremden Code seiner Lesbarkeit berauben...

    Ja, das stimmt schon. Das ist ein technisches Problem. Aber ich sehe so gut wie keine Use Cases für sowas und keine praktischen Probleme. Wenn eine Klasse intern Ressourcen verwaltet, ist es selbst eine Ressource und es macht auch Sinn, dass sie IDisposable implementiert. Und brauchen tut man das ganz ganz selten. Ich hab sicher schon mal Klassen geschrieben, die eine Datei oder andere Ressource offen halten, auch wenn ich mich grad nicht explizit dran erinnern kann und das sicherlich extrem selten vorkam. Aber das war sicher nichts, wo ich 10 000 von solchen Objekten im Programm verwalte. Das war dann vielleicht mal eine Klasse, die eine Datei offen gehalten hat, mein Gott, dann wird die notfalls halt etwas später zugemacht. Ich halte diese ganzen Probleme für nicht wirklich praxisrelevant.



  • Ich denke mal Mechanics wird von Microsoft gesponsert und will jetzt künstlich die Probleme kleinreden.


Anmelden zum Antworten