vergesst C++ ...



  • 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?



  • @Optimizer

    IMHO kann man sowas nur auf Sprachebene einschränken und nicht mit einem selbstgebauten Typ.

    So ein quatsch. Wenn eben jemand Zeiger manipuliert, dann ist er selbst schuld, wenn der GC ihm um die Ohren fliegt. Du könntest genauso behaupten, dass man mit C++ nicht programmieren kann, weil

    int *i=0x0;
    *i=10;
    

    möglich ist.

    C++ ist eben eine Sprache, die den Programmierer nicht vor sich selbst schützt. Das kann man meinetwegen an C++ kritisieren (oder auch lieben).



  • kingruedi schrieb:

    @Optimizer

    IMHO kann man sowas nur auf Sprachebene einschränken und nicht mit einem selbstgebauten Typ.

    So ein quatsch. Wenn eben jemand Zeiger manipuliert, dann ist er selbst schuld, wenn der GC ihm um die Ohren fliegt. Du könntest genauso behaupten, dass man mit C++ nicht programmieren kann, weil

    int *i=0x0;
    *i=10;
    

    möglich ist.

    C++ ist eben eine Sprache, die den Programmierer nicht vor sich selbst schützt. Das kann man meinetwegen an C++ kritisieren (oder auch lieben).

    👍 👍



  • TactX schrieb:

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

    siehe jedes beliebige algol-buch.



  • volkard schrieb:

    TactX schrieb:

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

    siehe jedes beliebige algol-buch.

    Thx 👍



  • O'Rakl schrieb:

    Python-Programme haben eine Eleganz und Kürze

    Obwohl ich für sowas immer zu haben bin, ist das wirtschaftlich gesehen praktisch bedeutungslos. Dort kommt es hauptsächlich darauf an, dass ein Produkt funktioniert (Kunde) und dass es wartbar ist (Entwickler). Kurze Entwicklungszeiten sind zwar immer gern gesehen, aber Eleganz und wenig Code stehen oftmals in keinem direkten Verhältnis dazu.

    O'Rakl schrieb:

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

    So hat halt jede Sprache ihre Vor- und Nachteile und damit ihre Einsatzgebiete. Hast du schon mal versucht, mit Python einen Emulator zu schreiben? Vermutlich nicht. Irgendwie hast du noch kein gutes Argument gebracht, warum man C++ wegen Python vergessen sollte. Und GC ist erst recht keines, da man in C++ schon lange bewährte Ressourcenmechanismen verwendet, die stetig verbessert werden, um mehr Sicherheit zu bekommen. Egal ob das jetzt über Sprachmittel realisert wird (zB Smart Pointer) oder über Compilerverbesserungen. Und GC ist dafür kein Allheilmittel, im Gegenteil, es hat nicht zu unterschätzende Nachteile. Nichtlineares Laufzeitverhalten ist zB einer, dh in Echtzeit Systemen ist GC praktisch nutzlos. Zudem ist das wichtigste immer noch, dass man Ressourcen sicher benutzen kann und nicht, dass diese automatisch freigegeben werden.
    Ausserdem sei noch erwähnt, so wie ich Orthogonalität verstehe, magst du gegenüber C Recht haben, aber C++ bietet da wesentlich mehr. Sicher gibt es auch hier Einschränkungen (zB keine Referenzen auf Referenzen), aber die wesentlichen Unterschiede, die dann über Eleganz und Codelänge entscheiden, liegen bei den syntaktischen Gegebenheiten. Und da spielt idR auch der persönliche Geschmack eine Rolle. Bisher hab ich nur einige Beispile in Python gesehen, die mich nicht wirklich vom Hocker gehauen haben. Dennoch würde ich nicht behaupten, dass man Python vergessen kann, weil C++ viel besser ist.

    O'Rakl schrieb:

    Ansonsten: Zeigerarithmetik, Pointer-Casting ("(void*)"...)

    Scheinbar denkst du zu viel C.

    O'Rakl schrieb:

    und Garbage Collection gleichzeitig geht nicht

    GC ist ein Konzept und beschreibt keine konkrete Implementierung. Mit konsequenter Benutzung von Smart Pointern hast du auch in C++ GC. 🙂



  • kingruedi schrieb:

    @Optimizer

    IMHO kann man sowas nur auf Sprachebene einschränken und nicht mit einem selbstgebauten Typ.

    So ein quatsch. Wenn eben jemand Zeiger manipuliert, dann ist er selbst schuld, wenn der GC ihm um die Ohren fliegt. Du könntest genauso behaupten, dass man mit C++ nicht programmieren kann, weil

    int *i=0x0;
    *i=10;
    

    möglich ist.

    C++ ist eben eine Sprache, die den Programmierer nicht vor sich selbst schützt. Das kann man meinetwegen an C++ kritisieren (oder auch lieben).

    Ach komm, warum habe ich extra zweimal erwähnt, dass man dazu nicht mutwillig die Arbeit des GC sabotieren muss? 👎
    Es reicht eine simple Übergabe eines Objekts per Referenz (und damit meine ich eine C++-Referenz), die kann intern auf einen Zeiger abgebildet werden und bumm. Oder ich hab ein char[], was natürlich vom GC verwaltet werden soll und geb nen char* mal schnell an ne DLL rüber, während der GC das bereinigen anfängt. Bumm.
    Warum meinst du, habe ich geschrieben

    Optimizer schrieb:

    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 ...

    damit du es nicht liest?

    groovemaster schrieb:

    Zudem zeigt es, dass GC unter C++ möglich ist, auch wenn man diesbezüglich Erweiterungen benötigt.

    Hach ja. Dann sind wir uns doch einig.

    Ich finde es nur etwas seltsam einer Sprache vorzuwerfen, dass sie kein GC erlaubt, obwohl sie dafür nie konzipiert war.

    Es war nie als Vorwurf formuliert. Bitte sag mir wie ich mich noch vorsichtiger ausdrücken kann als mit "dass _kann_ man als Nachteil auffassen, _wenn_ man einen GC mag..."



  • Vor einiger Zeit hab ich mich an einem GC für C++ versucht. Eigentlich war alles lösbarer Natur bis auf das Verschieben der Objekte. Der Knackpunkt heißt this. Das Problem ist, dass man in keiner Methode einen Heap komprimiren kann. Dies könnte ja den this Pointer verändern wodurch sämtliche Zugriffe auf das Objekt danach fehlschlagen. Mit Smartpointer ist hier nur mit einem sehr hässlichen Syntax etwas zu machen und sobald mehrer Threads ins Spiel kommen ist es nicht meher lösbar. Höchstens noch ein Hack der den this Pointer verändern würde.

    C++ braucht um GC fähig zu werden eine Spracherweiterung. GC-Spracherweiterung sind dazu allerdings nicht nötig. Legentlich muß man den this Pointer konsequent duch einen Smartpointer ersetzen können.



  • Ben04 schrieb:

    C++ braucht um GC fähig zu werden eine Spracherweiterung.

    So ein Käse. Es gibt GC System für C++, die auch funktionieren.

    Wichtig ist auf jeden Fall die Verwendung einer eigenen Referenz-Klasse, damit Objekte, die noch benutzt werden, nicht vom GC hopps genommen werden können. Das ist doch logisch, oder!


Anmelden zum Antworten