Warum faengt das Array bei 0 an?


  • Mod

    Baracke_out schrieb:

    Wichtig ist mir das nicht, war nur ne frage die mir im Kopf rumgeschwirrt ist und raus wollte. Und eigentlich ist 1 oder was auch immer unnoetig, blaeht nur denn Code auf.

    Aber warum in C++ keine Garbage Collection einfuehren kann ist mir nicht klar.

    1. Weil dann Code wie der hier gezeigt nicht mehr funktionieren würde. Und solche oder ähnliche Tricks werden recht oft benutzt. Und wenn man durch eine Erweiterung der Sprache allen Code der bisher existierte ksputt macht, dann macht man die Sprache kaputt. Das ist der Grund warum man keine GC einführen kann.

    2. Außerdem läuft bei Sprachen mit GC die Objekterzeugung und Vernichtung völlig anders. Man müsste die ganze Syntax der Sprache und die grundlegenden Mechnismen ändern. Folgen: Siehe Punkt 1.

    3. Außerdem sprechen auch sprachphilosophische Gründe dagegen: C++ ist eine abstrakte aber maschinennahe Sprache. Man kann ganz tolle Strukturen aufbauen, aber man hat dabei die volle Kontrolle über alles. Eine GC würde eine unkontrollierbare Zwischenschicht einführen. Das Anwendungsgebiet der Sprache würde sich dadurch komplett verlagern und es würde eher Richtung Java gehen. Dafür gäbe es dann aber keine abstrakte maschinennahe Sprache mehr.

    4. Ein etwas schwacher Punkt: Man braucht sie nicht. Mit den vorhandenen Sprachmechanismen ist es relativ einfach auch ohne GC auszukommen ohne nennenswerte Nachteile. Und falls man doch eine braucht, kann man sich auch trotzdem eine GC selber programmieren.



  • SeppJ schrieb:

    ...Und falls man doch eine braucht, kann man sich auch trotzdem eine GC selber programmieren.

    ... oder gleich java nehmen. 😉

    Soll kein C++-Bashing sein - ich bin nur ein großer Freund von "das richtige Werkzeug für die Aufgabe". Man fragt ja auch nicht, wann denn endlich in die Bohrmaschine eine Beilschneide eingebaut wird. 😉

    Gruß,

    Simon2.



  • SeppJ schrieb:

    Baracke_out schrieb:

    Wichtig ist mir das nicht, war nur ne frage die mir im Kopf rumgeschwirrt ist und raus wollte. Und eigentlich ist 1 oder was auch immer unnoetig, blaeht nur denn Code auf.

    Aber warum in C++ keine Garbage Collection einfuehren kann ist mir nicht klar.

    1. Weil dann Code wie der hier gezeigt nicht mehr funktionieren würde. Und solche oder ähnliche Tricks werden recht oft benutzt. Und wenn man durch eine Erweiterung der Sprache allen Code der bisher existierte ksputt macht, dann macht man die Sprache kaputt. Das ist der Grund warum man keine GC einführen kann.

    2. Außerdem läuft bei Sprachen mit GC die Objekterzeugung und Vernichtung völlig anders. Man müsste die ganze Syntax der Sprache und die grundlegenden Mechnismen ändern. Folgen: Siehe Punkt 1.

    3. Außerdem sprechen auch sprachphilosophische Gründe dagegen: C++ ist eine abstrakte aber maschinennahe Sprache. Man kann ganz tolle Strukturen aufbauen, aber man hat dabei die volle Kontrolle über alles. Eine GC würde eine unkontrollierbare Zwischenschicht einführen. Das Anwendungsgebiet der Sprache würde sich dadurch komplett verlagern und es würde eher Richtung Java gehen. Dafür gäbe es dann aber keine abstrakte maschinennahe Sprache mehr.

    4. Ein etwas schwacher Punkt: Man braucht sie nicht. Mit den vorhandenen Sprachmechanismen ist es relativ einfach auch ohne GC auszukommen ohne nennenswerte Nachteile. Und falls man doch eine braucht, kann man sich auch trotzdem eine GC selber programmieren.

    👍



  • Wenn du einen GC willst, empfehle ich dir D.

    Gruß



  • unmöglich schrieb:

    :hoppschwiiz: wxSkip schrieb:

    Und wenn in C++ beim nächsten Mal die Garbage Collection eingeführt wird, bist du auch blöd dran.

    Geht nicht.

    1. C++/CLI gibt es schon.
    2. hatte das ISO-Kommitee schon bei C++0x vor, die Garbage Collection optional einzuführen, hat es aber dann doch verschoben.



  • Ich kann SeppJ vollkommen zustimmen. Ein Garbage Collector passt meiner Meinung nach weder konzeptionell noch technisch zu C++. Er ist zwar ein wertvolles Werkzeug in anderen Sprachen, aber in C++ habe ich ihn nie vermisst.
    :hoppschwiiz: :hoppschwiiz: :hoppschwiiz:



  • Nexus schrieb:

    Ich kann SeppJ vollkommen zustimmen. Ein Garbage Collector passt meiner Meinung nach weder konzeptionell noch technisch zu C++.

    Naja, technisch vielleicht schon. Aber nicht in der Art wie in Java. Sondern nur als Memory-Collector. Soll heißen, daß man sehr wohl Destruktoren für das supi wertvolle RAII benutzt, aber Speicher vom GC aufräumen läßt. Soll heißen, daß man ihn einfach fallen läßt, außer ein Kind hat was Nichtspeicheriges, dann wird nur dieses Kind halt noch umgebracht. Könnte vielleicht ein paar Locks vermeiden und bei 12 Kernen überlegen viele Leute schon viel rum, Locks zu vermeiden als Standardrundumallheilmittel.
    Naja, noch brauche ich es nicht, denn ich habe entdeckt, daß bei mir entweder die Speicherbesorgung supi wenig Prozent der Gesamtlast ausmacht, oder bei meinem lustigen neverending Webserverplan, daß threadlokale Allokatoren, die man std::-containern ja frei unterschieben kann, das Mittel der Wahl sind.
    Ich hatte mal einen Simulator gebaut, wo verflixt viele Objekte sich freispeicherallkokierte Nachrichten geschickt hatten, und bei 10Mio Nachrichten pro Sekunde war new/delete schon ein Happen. Damals nur ein Kern. Konnte ich auf 70-mal so schnell wie new bringen. Aber mit 12 Kernen würde es ein reines Rumgewarte werden. Und zwar egal, wie ich die SmartPointers anlege, refcountig, Ring, pagetagging, naja, vielleicht geht es, nur weiß ich nicht, wie. Aber dann wissen es auch genügend viele Leute nicht, und viele, die sowas bauen, wünschen sich für C++ einen für diese eine Projektsorte zuschaltbaren GC.
    Damals gab es noch kein C#. Vielleicht wäre es besser, sowas in C# zu machen. Nee, auch nicht. Es brauchte auch high speed in Array-Zweckentfremdung und humeoresken Operator-Überladungen.
    D?



  • Den von dir beschriebenen GC finde ich interessant, ich habe bisher mehr an die klassischen gedacht. In C++ hat man zum Beispiel auch das Problem der Speicherfragmentierung, das in automatisch verwalteten Sprachen weniger auftritt. Vielleicht könnte man im Zusammenhang mit dem GC und speziellen indirekten Zeigern was Entsprechendes konstruieren... Schön finde ich, dass man in C++ prinzipiell diese Möglichkeit hat.

    Wobei man dann wieder gegen den Standard Krieg führen muss ("man darf nur PODs im Speicher verschieben"). Oder wäre das was für Move-Semantik in C++0x?

    volkard schrieb:

    threadlokale Allokatoren, die man std::-containern ja frei unterschieben kann

    Kann man das? Ich bin gerade kürzlich über diesen Thread gestolpert, in dem über statusbehaftete (und damit nicht-globale) STL-Allokatoren diskutiert wurde. Scheinbar ist das nicht so einfach... Oder hast du es unportabel hingekriegt?



  • wxSkip schrieb:

    1. C++/CLI gibt es schon.

    Hat C++/CLI wirklich einen GC? Ich ging davon aus, dass Blubb^ bla=gcnew Blubb ... eine Kurzform für etwa shared_ptr<Blubb> bla=shared_ptr<Blubb>(new Blubb...) ist.



  • Athar schrieb:

    wxSkip schrieb:

    1. C++/CLI gibt es schon.

    Hat C++/CLI wirklich einen GC? Ich ging davon aus, dass Blubb^ bla=gcnew Blubb ... eine Kurzform für etwa shared_ptr<Blubb> bla=shared_ptr<Blubb>(new Blubb...) ist.

    Ich weiß nicht genau, wie das gemacht wird, lediglich, dass der Speicher automatisch verwaltet wird. Über shared_ptr bin ich auch unzureichend informiert.



  • Wie soll das mit nem GC gehen? Wenn ich irgendeine alte Lib habe, die den Speicher schon selber aufräumt und plötzlich macht es de GC nochmal?



  • 9tiere schrieb:

    Wie soll das mit nem GC gehen? Wenn ich irgendeine alte Lib habe, die den Speicher schon selber aufräumt und plötzlich macht es de GC nochmal?

    Wenn sich free() bzw. delete und delete[] merken, was sie gelöscht haben, weiß es ja der GC und der löscht es dann nicht mehr.



  • Athar schrieb:

    wxSkip schrieb:

    1. C++/CLI gibt es schon.

    Hat C++/CLI wirklich einen GC? Ich ging davon aus, dass Blubb^ bla=gcnew Blubb ... eine Kurzform für etwa shared_ptr<Blubb> bla=shared_ptr<Blubb>(new Blubb...) ist.

    Nein, es handelt sich wirklich um einen GC und die bla befindet sich im Managed Heap.



  • Nexus schrieb:

    Wobei man dann wieder gegen den Standard Krieg führen muss ("man darf nur PODs im Speicher verschieben"). Oder wäre das was für Move-Semantik in C++0x?

    Ich gehe nicht von Verschieben aus. Und ich gehe davon aus, daß das Verschieben in Sachen Cache-Zeugs nix bringt. Das Senken der internen Fragmentierung ist mir recht egal, da ich nichtmal bei **** einen Rechner mit weniger als 4G RAM finde. Mein bester Freund dahingehend heißt Buddy und der andere ist Alexandrescu.

    Nexus schrieb:

    Oder hast du es unportabel hingekriegt?

    Natürlich unportabel. C++ kennt keine Threads. Ein threadlokaler void* reicht. Das bieten alle. Aber wie ihn kriegen? (Im Sonderausnahemfall meiner HTTP-Server-Planung war es "portabel" insoweit, daß jedes angestrebte BS dem neuen Thread Stackspeicher gibt und ich erstmal ein char[65536] anlege und daraus schöpfe. Wenn alle, dann Error-Response). Ich denke zur Zeit an eibnen Threadlokalen void*, der auf einen nur für diesen Thread per memory mapping allokierten 64k-Bereich zeigt, dessen Seiten erst bei Zugriff physikalisch hinterlegt werden. Linux und Win können das mit fast gleichen Befehlen und einfach und übersichtlich ist es auch. Den Zeiger auf den Speicherbereich, den ich zu Threadstart reserviere, kann ich entweder immer runterrreichen, oder im threadlokalen globalen Speicher ablegen. Das ist Jacke wie Hose.
    Viel schlimmer ist, daß ich gerade kein Kreuz-Bit finde und deswegen einen Rechner nicht aufschrauben kann. Ich will morgen früh nicht den Hausmeister um einen passenden Schraubendreher anbetteln müssen.



  • volkard schrieb:

    Das Senken der internen Fragmentierung ist mir recht egal, da ich nichtmal bei **** einen Rechner mit weniger als 4G RAM finde. Mein bester Freund dahingehend heißt Buddy und der andere ist Alexandrescu.

    Buddy-System und Small-Object-Allocator? Ich müsste sowas endlich mal richtig anwenden. Bisher waren meine Projekte zu wenig ressourcenfessend, als dass new und delete nicht gereicht hätten. Meistens liegt das Performanceproblem auch woanders, da ich viel mit Grafik programmiere.

    volkard schrieb:

    Im Sonderausnahemfall meiner HTTP-Server-Planung war es "portabel" insoweit, daß jedes angestrebte BS dem neuen Thread Stackspeicher gibt und ich erstmal ein char[65536] anlege und daraus schöpfe. Wenn alle, dann Error-Response

    Ich nehme an, damit deckst du wahrscheinlich schon viele kleine Anforderungen ab... Klingt gut. Kann man eigentlich Stackspeicher gut für Placement New benutzen (wegen möglichen Alignmentproblemen, aber keine Ahnung wie praxisrelevant die tatsächlich sind)? Und Overflows abzufangen ist nicht mühsam?



  • Nexus schrieb:

    Ich nehme an, damit deckst du wahrscheinlich schon viele kleine Anforderungen ab... Klingt gut. Kann man eigentlich Stackspeicher gut für Placement New benutzen (wegen möglichen Alignmentproblemen, aber keine Ahnung wie praxisrelevant die tatsächlich sind)?

    Klar. Man nehme den

    void* alloc(size_t size){
       size=aufrundenAufAllesAlignment(size);//je nach dem, bei mir 8
       char* result=threadLocalTop+size;
       threadLocalTop+=size;
       if(threadLocalTop>threadLocalMax)//nonstandard, aber klappt faktisch immer
          throw Bla
       return result;
       //Keine Verkettung
    }
    void free(void* hihihi_HEHEHE_hohoho){
       //Hihi, bei Threadende geht's eh weg. 
    }
    

    [cpp]Und Overflows abzufangen ist nicht mühsam?[/quote]
    Ja, das ist doof, weil es ein if mehr kostet. Ich habe gar nicht daran gedacht, das auch noch einzusparen und der MMU aufzudrücken. Doch, habe ich. Aber nee, das ist es nicht wert. Mit if geht win/linux gleich und benutzt "Standardmittel", die jedes BS hat.



  • volkard schrieb:

    Könnte vielleicht ein paar Locks vermeiden und bei 12 Kernen überlegen viele Leute schon viel rum, Locks zu vermeiden als Standardrundumallheilmittel.

    Eventuell stehe ich gerade auf dem Schlauch, aber wo brauch man Locks bei new und delete?

    EDIT: Meinst du wenn z. B. shared_pointer in einem Objekt sind?
    Okay... Dann ist es klar. Oder auch anders?



  • volkard schrieb:

    Ich hatte mal einen Simulator gebaut, wo verflixt viele Objekte sich freispeicherallkokierte Nachrichten geschickt hatten, und bei 10Mio Nachrichten pro Sekunde war new/delete schon ein Happen.

    Was hast du für ein Netzwerk, damit new und delete die großen Performancebremsen sind?



  • ??????????? schrieb:

    volkard schrieb:

    Ich hatte mal einen Simulator gebaut, wo verflixt viele Objekte sich freispeicherallkokierte Nachrichten geschickt hatten, und bei 10Mio Nachrichten pro Sekunde war new/delete schon ein Happen.

    Was hast du für ein Netzwerk, damit new und delete die großen Performancebremsen sind?

    Verzögerte Funktionsaufrufe, indem Aufwachzeitpunkt, Funktionszeiger und zur Funktion passende Parameter in ein Nachricht-Objekt gestopft werden, das von Basisnachricht erbt. Wegen Polymorphie liegt new recht nahe. Die Nachrichtenzeiger werden in einer Prioitätswarteschlage gehalten. Der Aufrufer ruft nicht mehr die Funktion auf, sondern baut eine Nachricht und wirft sie auf den großen Haufen. Und es gibt keine Akteure, die sowas kompliziertes wie Wegfindung, Grafik oder pseudointelligentes Verhalten brauchen. Die aufgerufenen Funktionen sind alle recht billig.



  • CSpille schrieb:

    volkard schrieb:

    Könnte vielleicht ein paar Locks vermeiden und bei 12 Kernen überlegen viele Leute schon viel rum, Locks zu vermeiden als Standardrundumallheilmittel.

    Eventuell stehe ich gerade auf dem Schlauch, aber wo brauch man Locks bei new und delete?

    Gehts auch ohne? Ich will den Speicherblock doch wieder in die verkettete Liste hängen oder Baum, Heap, oder mit Nachbarn verschmelzen oder nur den freispeicherzähler inkrementieren, ohne daß ein anderer Thread auch an meinen Nachbarn rumfummelt oder gleichzeitig Zähler ändert.


Anmelden zum Antworten