vergesst C++ ...



  • volkard schrieb:

    win95 kackte fast täglich ab und win98 nur noch alle 2 wochen. bei normaler installation, 10 stunden benutzung am tag. aber wer hatte schon ein sauberes system? netzwerkkarten und grafikkarten verlangten treiberdisketten, die treiber waren so unsauber und win9x so empfindlich gegen unsaubere treiber, daß es eigentlich nur daran lag. die meisten, die auch win98 hatten, hatten viel viel mehr abstürze als ich mit meiner on-board-graka und nur ms-treibern.

    Wenn Windows 95 sauber installiert war, mit guten Treibern, war es durchaus sehr stabil und stürzte selten ab. Ich hatte mal einen Rechner mit Windows 95, der rund um die Uhr lief, ohne oft abzustürzen. Meist kam das nur, wenn fehlerhafte Programme sich aufgehängt hatten. Dasselbe galt auch für Windows 98. Da die Windows 95, 98 und ME Linie aus 16-/32-Bit-Hybridsystemen besteht, ist das auch nicht weiter verweunderlich.

    Die Windows NT Linie, also Windows NT, 2000 und XP (und jetzt Vista) sind deutlich stabiler, weil sie "reine" 32-Bit-Systeme sind (von den 16-Bit-Kompatibilitätslayern für MS-DOS, Windows 3.x und OS/2 1.x mal abgesehen, die jedoch der Speicherüberwachung durch die MMU unterliegen). Ich nehme an, daß bei diesen Systemen der Prozessor primär im Protect Mode läuft, während bei den Hybridsystemen der Prozessor oft im ungeschützten V86-Mode lief (hoffe, meine Terminologie hier stimmt).



  • O'Rakl schrieb:

    Aber ich gestehe zu, daß man nicht leicht merkt, wie viel Arbeit man bei C++
    investiert in Dinge, die eigentlich der Compiler machen soll
    (Zeiger, Referenzen, Speicherverwaltung, Garbage Collection,...)

    Du hast noch nie wirklich C++ programmiert, oder?
    Leider geht es wie dir vielen Leuten, die nie richtig gelernt haben, mit C++ umzugehen. Mit Speicherverwaltung kommt man praktisch nie in Berührung, sondern benutzt bequeme Container. Da fällt höchstens mal ein foo.reserve(bla) an, aber auch nur wenn's um Laufzeiteffizienz geht. Das Problem ist einfach, dass zu viele Programmierer sich dessen nicht bewusst sind und einfach new verwenden. Sie haben das ja mal so gelernt. Und am Ende vergessen sie natürlich mit delete wieder alles freizugeben.
    Zeiger wirst du nur sehr spärlich verwenden. Wobei das natürlich auch davon abhängt, wie hardwarenah du programmieren möchtest. Referenzen möchte ich persönlich nicht missen und wüsste jetzt nicht, wieso die mich zu viel Zeit kosten. Für Garbage Collection gibt es unter C++ keinen Grund, weil praktisch alle Implementierungen scope-basiertes Freigeben von Ressourcen verfolgen (was imo vorteilhafter ist).

    GPC schrieb:

    Was ist Orthogonalität bei einer Programmiersprache, ich kenne das eigentlich eher aus Mathe und Vektorenrechnung 😕

    Das frage ich mich auch schon die ganze Zeit.

    volkard schrieb:

    win95 kackte fast täglich ab und win98 nur noch alle 2 wochen.

    Da hab ich ähnliche Erfahrungen gemacht. Wobei es mir so vorkommt, dass spätere Win95 Versionen (B, C) etwas stabiler waren. Aber gerade frühe A Versionen waren teilweise richtig grausam.



  • O'Rakl schrieb:

    Aber ich gestehe zu, daß man nicht leicht merkt, wie viel Arbeit man bei C++
    investiert in Dinge, die eigentlich der Compiler machen soll
    (Zeiger, Referenzen, Speicherverwaltung, Garbage Collection,...)

    Nein, ein Garbage Collector hat nichts mit dem Compiler zu tun und läuft nebenbei, wenn du das Programm ausführst. Für C++ gibt es übrigens auch GCs (Bsp. http://www.hpl.hp.com/personal/Hans_Boehm/gc/)



  • @Groovemaster:
    <Für Garbage Collection gibt es unter C++ keinen Grund,>

    GC ist aus einer modernen, abstrakteren Sprache nicht wegzudenken, denn alles, was der Compiler oder die Runtime erledigen kann, sollte nicht dem Programmierer
    aufgelastet werden.
    Die Wahrheit ist eher: C++ erlaubt gar keine GC, denn das ist mit einem
    Zeigerkonzept und dem Casting (void*) unverträglich. Wenn die GC einen Speicherbereich freigegeben würde,
    wüßte sie nicht, ob nicht im nächsten Augenblick ein Zeiger umgebogen
    wird, der zunächst noch auf etwas ganz Anderes zeigte, um nun auf den
    soeben freigegebenen Speicherbereicht zu zeigen:
    Bingo.
    <segmentation fault - address violation at 0x0012:3456>

    <Mit Speicherverwaltung kommt man praktisch nie in Berührung, sondern benutzt bequeme Container>

    Nach dem Studium von weit über tausend Seiten C++-Referenz bin ich
    nicht mit Containern in Berührung gekommen, aber ständig mit
    new, delete, malloc etc.
    Wenn die simple Aufgabe, einen Speicherbereicht sicher zu belegen und
    vor allem sicher wieder freizugeben, mehr als 1500 Seiten Lektüre erfordert,
    dann -- da werden wir uns doch einig sein -- stimmt mit einer solchen
    Programmiersprache didaktisch und womöglich konzeptuell etwas ganz entschieden nicht.



  • Ergänzung: Mit Containern bin ich schon
    in Kontakt gekommen, allerdings habe ich nicht gesehen, wieso dadurch
    eine Speicherverwaltung generell überflüssig würde.
    Spätestens beim Implementieren eigener Klassen, die im Konstruktor Speicher belegen und im Destruktor wieder freigibt, hat man es mit klassischen Garbage-Collection-Aufgaben
    zu tun.



  • O'Rakl schrieb:

    denn alles, was der Compiler oder die Runtime erledigen kann, sollte nicht dem Programmierer
    aufgelastet werden.

    Sehe ich genauso. Nur wozu soll das ein Widerspruch sein?

    O'Rakl schrieb:

    Die Wahrheit ist eher: C++ erlaubt gar keine GC, denn das ist mit einem
    Zeigerkonzept und dem Casting (void*) unverträglich.

    Unsinn. MS nutzt für C++/CLI ebenfalls GC.

    O'Rakl schrieb:

    Wenn die GC einen Speicherbereich freigegeben würde,
    wüßte sie nicht, ob nicht im nächsten Augenblick ein Zeiger umgebogen
    wird, der zunächst noch auf etwas ganz Anderes zeigte, um nun auf den
    soeben freigegebenen Speicherbereicht zu zeigen:
    Bingo.
    <segmentation fault - address violation at 0x0012:3456>

    Das ist doch kein Problem einer Speicherverwaltung. Zeiger kann man nunmal auf jede beliebige Adresse verweisen lassen. Und wenn dieser Bereich dir nicht gehört, dann hast du auch kein Recht darauf zuzugreifen. Und wenn Non-Client Code auf ungültige Bereiche zugreift, dann ist das ein Problem der Speicherverwaltung bzw. der verwendeten Container, egal ob GC oder nicht.

    O'Rakl schrieb:

    Nach dem Studium von weit über tausend Seiten C++-Referenz bin ich
    nicht mit Containern in Berührung gekommen, aber ständig mit
    new, delete, malloc etc.

    Genau darüber hab ich ja gesprochen. Zu viele Leute machen sich das Leben zu schwer, weil sie es einfach nie richtig gelernt haben. Ich bin zwar ein Befürworter, dass man sich gerade in C++, bevor man sich auf Bibliotheken wie STL oder Boost stürzt, die Grundlagen aneignen sollte, aber danach sollte man auf jedenfall die Funktionalität dieser oder anderer Bibliotheken nutzen.

    O'Rakl schrieb:

    Wenn die simple Aufgabe, einen Speicherbereicht sicher zu belegen und
    vor allem sicher wieder freizugeben, mehr als 1500 Seiten Lektüre erfordert,
    dann -- da werden wir uns doch einig sein -- stimmt mit einer solchen
    Programmiersprache didaktisch und womöglich konzeptuell etwas ganz entschieden nicht.

    Geb ich dir absolut Recht. Aber was hat das mit C++ zu tun?

    O'Rakl schrieb:

    Spätestens beim Implementieren eigener Klassen, die im Konstruktor Speicher belegen und im Destruktor wieder freigibt, hat man es mit klassischen Garbage-Collection-Aufgaben
    zu tun.

    Nö. Du kannst in Klassen natürlich auch Container verwenden und musst dich nicht um Speicherverwaltung kümmern. Und das alles ohne GC.



  • Die Wahrheit ist eher: C++ erlaubt gar keine GC, denn das ist mit einem Zeigerkonzept und dem Casting (void*) unverträglich

    Die Wahrheit scheint mir eher dass du keine Ahnung hast, erstens hat kingruedi grad nen Link zur GarbageCollection gepostet und zweitens sind auch SmartPointer irgendwie "Garbage-Collectoren". Bloß nebenbei: Durch SP kann man oft normale Zeiger vermeiden (siehe Glib::RefPtr)

    Spätestens beim Implementieren eigener Klassen, die im Konstruktor Speicher belegen und im Destruktor wieder freigibt, hat man es mit klassischen Garbage-Collection-Aufgaben
    zu tun

    Stimmt zwar mehr oder weniger, allerdings sind diese in einer Klasse gekapselt und können so besser überwacht und gesteuert werden, somit ist es unwahrscheinlicher dass man mal ein delete vergisst. Wozu hat man schließlich Ctors und Dtors? Wer schlampig programmiert, klar, der pisst sich selber an.



  • Ich glaube Smart Pointer ist für Orakel generell ein guter Tipp. Genug Lektüre dazu sollte ja im Netz zu finden sein.



  • Ich stimme mit O'Rakl fast nirgendwo überein, aber im Punkt mit der GC hat er Recht.
    @groovemaster: C++/CLI ist kein Standard-C++. Nur mit Hilfe der Erweiterungen lassen sich Objekte erstellen, die auch wieder vom GC gefressen werden. Der Grund ist auch vollkommen klar, gewöhliche rohe Zeiger, die alles erlauben, sind vollkommen unbrauchbar, um damit auf einem verwalteten Heap zu arbeiten. Ein ordentlicher Garbage Collector verschiebt Objekte, weswegen spezielle Zeiger erforderlich sind, die entweder dem GC bekannt sind, damit er sie ändern kann, oder die über eine zusätzliche Indirektion verfügen. Vor allem aber, darf es nicht möglich sein, an die Adresse eines Objekts auf dem GC-Heap ranzukommen oder gar damit zu rechnen. In C++ kannst du von allem die Adresse holen, damit ist eine große Unsicherheit schon gegeben.

    @kingruedi: Der von dir genannte GC ist unter keinen Bedingungen konkurrenzfähig zu einem "anständigen" GC, weder in Punkto Sicherheit, noch Performance. Der GC kann Zeiger auf ein Objekt nur erkennen, wenn du wirklich einen Zeiger darauf hast. Wenn du dir über Pointerarithmetik die Adresse des Objekts ausrechnest, erkennt er das nicht und entfernt es. Außerdem ist der Collector konservativ und erkennt damit generell schon nicht alle unbrauchbaren Objekte.
    Bei der Performance wird es richtig schlimm. Normale GCs müssen aufwändig nach Verweisen auf Objekte suchen, was sie aber sehr optimieren können, indem sie Generationen benutzen. Ein Mark & Sweep Collector kann aber keine Generationen haben, da er den Heap nicht kompaktiert. Weiterhin ist das ändern der Freispeicherliste bei einer Bereinigung wesentlich aufwändiger, als das Verschieben der lebenden Objekte. Dieser GC hat also mehr Arbeit beim Auffinden der Objekte und beim Bereinigen dieser. Das Auffinden ist nochmal zusätzlich aufwändig, weil der GC alle 4 Byte-Blöcke auf dem Stack und auf dem Heap als Pointer annehmen muss und dementsprechend mehr mögliche Pointer prüft als ein GC, der entsprechende Metadaten zur Verfügung hat.

    Fazit: Mit Standard C++ ist weder ein sicherer (im Sinne von "macht nix weg, was ich noch brauch, macht alles weg, was ich nicht mehr brauch) noch ein performanter GC möglich, so wie in C++/CLI mit Erweiterungen direkt an der Sprache ist es die einzige Möglichkeit. Das kann man, wenn man GCs mag, als Nachteil von C++ auffassen, so einsichtig könntet ihr schon sein. 😉



  • Optimizer schrieb:

    @kingruedi: Der von dir genannte GC ist unter keinen Bedingungen konkurrenzfähig zu einem "anständigen" GC, weder in Punkto Sicherheit, noch Performance. Der GC kann Zeiger auf ein Objekt nur erkennen, wenn du wirklich einen Zeiger darauf hast. Wenn du dir über Pointerarithmetik die Adresse des Objekts ausrechnest, erkennt er das nicht und entfernt es. Außerdem ist der Collector konservativ und erkennt damit generell schon nicht alle unbrauchbaren Objekte.
    Bei der Performance wird es richtig schlimm. Normale GCs müssen aufwändig nach Verweisen auf Objekte suchen, was sie aber sehr optimieren können, indem sie Generationen benutzen. Ein Mark & Sweep Collector kann aber keine Generationen haben, da er den Heap nicht kompaktiert. Weiterhin ist das ändern der Freispeicherliste bei einer Bereinigung wesentlich aufwändiger, als das Verschieben der lebenden Objekte. Dieser GC hat also mehr Arbeit beim Auffinden der Objekte und beim Bereinigen dieser. Das Auffinden ist nochmal zusätzlich aufwändig, weil der GC alle 4 Byte-Blöcke auf dem Stack und auf dem Heap als Pointer annehmen muss und dementsprechend mehr mögliche Pointer prüft als ein GC, der entsprechende Metadaten zur Verfügung hat.

    Fazit: Mit Standard C++ ist weder ein sicherer (im Sinne von "macht nix weg, was ich noch brauch, macht alles weg, was ich nicht mehr brauch) noch ein performanter GC möglich, so wie in C++/CLI mit Erweiterungen direkt an der Sprache ist es die einzige Möglichkeit. Das kann man, wenn man GCs mag, als Nachteil von C++ auffassen, so einsichtig könntet ihr schon sein. 😉

    Einen GC kann man eben nicht benutzen, wenn man Zeigerarithmetik nutzt. Daher bieten weder Java, noch C++/CLI noch C# Zeigerarithmetik an. Aber vermutlich kann man einen GC auch wunderbar für C++ bauen, wenn man sich einen "Referenz"-Typ baut. C++/CLI macht das ja so (okay, sie implementieren es als Spracherweiterung). Hier kann doch C++ sehr wohl punkten, dadurch dass man leicht eigene Typen implementieren kann, die sich builtin Typen ziemlich ähnlich verhalten.

    So wie man nicht sagen kann, dass man Destruktoren in einer GC Sprache haben will, kann man nicht sagen, dass man Zeiger in einer GC Sprache haben will.



  • Destruktoren sind auch mit GC möglich und letztlich ist finally in Java/C# und unwind-protect in lisp (war es lisp?) Sprachmittel für die deterministische Destruktion. Dass die Destruktoren in C++ nicht explizit aufgerufen werden müssen ist nur Compiler-Zucker und hat vor und Nachteile (ein Nachteil in C++ ist, dass es möglicherweise mal was zu tun gibt, was designtechnisch nicht in einen Objekt-Destruktor passt. Daher gibt es auch finally in C++/CLI).

    Und wie kannst du einen Referenztyp bauen, der verhindert, dass du an die Adresse eines Objekts kommst? Du könntest mir jetzt natürlich Böswilligkeit unterstellen und C++ soll vor Böswilligkeit ja gar nicht schützen - aber schon das Übergeben eines Objekts als Referenz (&) kann intern das Übergeben eines Zeigers sein. Rohe Zeiger machen alle Sicherheit beim GC-Heap kaputt und solange man von allem die Adresse holen kann, ob beabsichtigt oder nicht, ob explizit oder nicht, ist es böse. IMHO kann man sowas nur auf Sprachebene einschränken und nicht mit einem selbstgebauten Typ.



  • Theoretisch wäre es schon möglich eine Entwicklungs- und Laufzeitumgebung für C++ zu machen, die Garbage Collection benutzt, und trotzdem Pointerarithmetik etc. unterstützt.

    Im Prinzip liegt der Hund im Pointertyp verbuddelt; wenn der Pointer keine Maschinenadresse sondern eine Art Deskriptor ist, dann ist es möglich z.B. Unter- und Obergrenzen sowie ein GC-Handle unterzubringen.

    Man muß nur wollen! 😉



  • Ohne alles gelesen zu haben und in der Hoffnung, dass folgendes noch nicht genannt wurde, möchte ich loswerden, was mir an C++ nicht gefällt:

    - die statische Typisierung
    - Funktionen sind nicht Variablen "erster Klasse"; Functors sind in C++ mühselig
    - keine Closures (geht aus obigem Punkt hervor)



  • Doktor Prokt schrieb:

    - Funktionen sind nicht Variablen "erster Klasse"; Functors sind in C++ mühselig
    - keine Closures (geht aus obigem Punkt hervor)

    Welche Sprachen können das? Gibt's außer JavaScript (ECMAScript) noch andere?



  • Optimizer schrieb:

    @groovemaster: C++/CLI ist kein Standard-C++.

    Das ist richtig, wir sind aber auch im RudP Forum. Zudem zeigt es, dass GC unter C++ möglich ist, auch wenn man diesbezüglich Erweiterungen benötigt. Ich finde es nur etwas seltsam einer Sprache vorzuwerfen, dass sie kein GC erlaubt, obwohl sie dafür nie konzipiert war. Genauso könnte ich einer Sprache vorwerfen, keine Zeiger zu unterstützen, obwohl das nie vorgesehen war.

    Optimizer schrieb:

    In C++ kannst du von allem die Adresse holen, damit ist eine große Unsicherheit schon gegeben.

    Wenn es um builtin Typen geht, dann hast du Recht. Darin liegt aber auch eine gewisse Verantwortung, über die man sich jetzt streiten kann, ob diese dem Programmierer denn unbedingt aufgezwungen werden muss. Fakt ist, dass rohe Zeiger bzw "echte" Adressen in C/C++ ihre Einsatzgebiete haben. Deshalb kann man nicht so tun, als ob rohe Zeiger ein unbrauchbares Übel sind, nur weil man GC gerne möchte.

    Optimizer schrieb:

    Fazit: Mit Standard C++ ist weder ein sicherer (im Sinne von "macht nix weg, was ich noch brauch, macht alles weg, was ich nicht mehr brauch) noch ein performanter GC möglich, so wie in C++/CLI mit Erweiterungen direkt an der Sprache ist es die einzige Möglichkeit. Das kann man, wenn man GCs mag, als Nachteil von C++ auffassen, so einsichtig könntet ihr schon sein. 😉

    Wer GC unbedingt möchte, wird unter Standard-C++ momentan sicher nicht glücklich werden. Der sollte sich vielleicht eher D anschaun. 🙂 Da ich aber keine Notwendigkeit für GC in C++ sehe, kann ich diesbezgl. auch keinen Nachteil feststellen.

    Doktor Prokt schrieb:

    was mir an C++ nicht gefällt:

    - die statische Typisierung

    Gerade dies ist eine der besten Sachen an C++. Statische Typisierung heisst ja nicht, dass man auf dynamische Typisierung verzichten muss. Auch wennn C++ da im Moment noch ziemlich schwachbrüstig ist. Lediglich die Syntax der Typisierung gefällt mir in Java oder D besser.



  • <Statische Typisierung heisst ja nicht, dass man auf dynamische Typisierung verzichten muss.>

    Wie geht denn dynamische Typisierung in C++ ?

    Ansonsten: Zeigerarithmetik, Pointer-Casting ("(void*)"...)
    und Garbage Collection gleichzeitig geht nicht. Und wenn es doch ginge,
    gäbe es keine Standard-Collection für C++ und damit wären Klassen nicht mehr
    zwengsläufig untereinander kompatibel, wenn sie auf verschiedenen
    Collection-Mechanismen angewiesen sind.

    Aber mal etwas genereller:
    Python-Programme haben eine Eleganz und Kürze, die einfach C++ nicht
    erreichen kann, selbst bei raffiniertester Anwendung der STL.
    Das liegt eben wesentlich an der dynamischen Typisierung und der
    Orthogonalität.



  • O'Rakl schrieb:

    Wie geht denn dynamische Typisierung in C++ ?

    Über virtuelle Basisklassen.



  • Power Off schrieb:

    O'Rakl schrieb:

    Wie geht denn dynamische Typisierung in C++ ?

    Über virtuelle Basisklassen.

    wie elegant..



  • O'Rakl schrieb:

    Aber mal etwas genereller:
    Python-Programme haben eine Eleganz und Kürze, die einfach C++ nicht
    erreichen kann, selbst bei raffiniertester Anwendung der STL.
    Das liegt eben wesentlich an der dynamischen Typisierung und der
    Orthogonalität.

    eleganz und kürze is auch nich alles
    ich mag prinzipiell keine zusätzlichen kontrollstrukturen zwischen mir und dem rechner... wer sauber programmiert und weiß was er tut hat eh keine probleme mit den lowlvl mechanismen
    @GC imho führt sowas zu verschwenderischen und trägen programmen, sowohl in der software selber als auch im stil der programmierer



  • O'Rakl schrieb:

    Das liegt eben wesentlich an der dynamischen Typisierung und der
    Orthogonalität.

    Was ist denn diese famose Orthogonalität? Oder ist das nur ein BWLer-Buzzword?


Anmelden zum Antworten