Buffer erweitern



  • Hi,

    sorry, hab grad nochmal eine Frage.
    Was kann ich denn machen, wenn ich an einer performancekritischen Stelle einen Buffer erweitern will und nicht etwas in der Art

    p2 = new char[CurSize + Erweitung];
    memcpy(p2, p, CurSize);
    delete[] p;
    p = p2
    

    machen will?

    Und dann noch eine Frage: Worin genau besteht der Unterschied zwischen delete und delete[]? Bitte jetzt keine Antworten wie das eine ist für eine Element, das andere für Arrays oder so, so ein Anfänger bin ich dann doch nicht.

    Die Sache ist bei mir nämlich so, dass ich einen Blob habe (ich denke, ihr wisst, was das ist) und die Daten werden zwar mit new char[size] allokiert, aber das dient ja nur dazu, die Größe festzulegen und nicht wirklich ein Array anzulegen. Der Zeiger wird dann als void* abgespeichert. Muss ich den dann später mit delete oder delete[] freigeben?

    ChrisM



  • ChrisM schrieb:

    Was kann ich denn machen, wenn ich an einer performancekritischen Stelle einen Buffer erweitern will

    stl-Container?

    ChrisM schrieb:

    Worin genau besteht der Unterschied zwischen delete und delete[]? Bitte jetzt keine Antworten wie das eine ist für eine Element, das andere für Arrays oder so

    Naja, das ist aber die Antwort darauf.
    Bei new char[x]; spricht man von einem Array. Egal ob du dann später nur einen void-Zeiger darauf hast.

    Löschen über void* geht nicht. Müsstest du erst zurück nach char* casten.. Spricht was dagegen einfach gleich einen char* zu speichern?

    Ansonsten könntest du auch malloc nehmen.. Da haste dein void*.



  • einen buffer erweitert man an performance kritischen stellen nicht, denn ein buffer der erweitert wird - muss neu angelegt werden.

    deswegen nimmt man entweder einen buffer der gross genug ist, oder eine datenstruktur die keine reallokation braucht (zB eine liste)



  • Hi,

    Liste oder Vector ist aber schlecht bei mir, denn ich will ja einen Blob erstellen, also eine Klasse mit write()/read()-Funktionen, die beliebige binäre Rohdaten speichern kann.
    Ist halt nur ärgerlich, wenn man dann write() mit einem Byte aufruft und jedesmal der Buffer vergrößert wird.

    Eine andere Lösung wäre halt, immer gleich doppelt so viel Speicher zu allokieren, wie man braucht. Dann würde die Zahl der Reallokierungen sinken, aber dafür würde viel Speicher verschwendet!

    ChrisM



  • wenn du keine liste willst, musst du halt mit intelligenter allokator strategie arbeiten.



  • Hi,

    wie macht das überhaupt std::vector? Der kann ja auch nicht erweitern und muss auch immer im voraus allokieren, oder?

    ChrisM



  • Er kann z.B. in reserve() einen neuen, größeren Buffer allozieren, die alten Elemente hineinkopieren und dann den alten Buffer löschen.



  • ChrisM schrieb:

    wie macht das überhaupt std::vector? Der kann ja auch nicht erweitern und muss auch immer im voraus allokieren, oder?

    exakt. deswegen muss man bei vector aufpassen, das man immer schoen reserve() aufruft - um diese allokation/umkopieren an nicht kritischen stellen zu erledigen...

    es gibt diverse allokations strategien, aber im endeeffekt ist es immer am besten, wenn du selber reserve() aufrufst - denn du weisst wohl am besten wieviele objekte da jetzt ungefaehr kommen...

    lieber n bisschen speicher verschwenden als den vector kopieren (sofern diese kopien teuer sind) - bei einem vector<int> oder so ist es egal.



  • Hi,

    gut, eine Frage noch:
    Unter C gabs ja malloc(), free() und realloc().

    Das erste (mit einigen Erweiterungen wie ctor-Aufruf) wurde zu new, das zweite zu delete. Warum wurde das dritte nicht umgesetzt?

    Das eine Allokationserweitungen möglich ist, zeigt ja realloc()!

    Komplett neu allokieren müsste man dann nur, wenn der Speicher hinter dem zu erweiternden Block halt schon vergeben ist (unwahrscheinlich)...

    ChrisM



  • realloc() macht bei den meisten Implementierungen wahrscheinlich auch nichts anderes als vector<T>::reserve() (s.o.). Kann man auch daran erkennen, dass realloc() einen neuen Zeiger zurückgibt.

    EDIT: Es wäre auch kein Problem für einen vector, einen auf 2^n aufgerundeten Block zu allozieren. Der Standard lässt das offen, es liegt nur an den Implementierern.



  • ChrisM schrieb:

    Hi,
    sorry, hab grad nochmal eine Frage.
    Was kann ich denn machen, wenn ich an einer performancekritischen Stelle einen Buffer erweitern will und nicht etwas in der Art

    a)
    dann nimmste mal sachen, die nicht standard-c++ sind. in der annahme, daß du nen prozessor mit virtuellem speicher hast, kannste billig vorher 200MB (oder was du halt maximal brauchst) des adressraums reservieren und dann in 4k-abschnitten darauf echtes ram mappen. netterweise gehts auch ganz ohne if nach jedem schreiben, wenn du die schutzverletzung bei pufferüberlauf fangen kannst und dadrin mit eigenem code den puffer vergrößern kannst.

    b)
    wenn man mit herkömmlichen mitteln arbeitet und die puffergroße immer verdoppelt, gibts eigentlich auch kein porformanceproblem. manchmal ein ruckeln? ja, aber nach 10 rucks hat sich die größe vertausendfacht.

    c)
    shared memory anlegen, der ist afair auch nicht anfangs im ram, sondern erst, wenn man tatsächlich was reinschreibselt.



  • wieso eigentlich 'new char [...]'? Wenn man einfach speicher will nimmt man doch normalerweise 'operator new (...)'


Anmelden zum Antworten