Designfrage - Dynamisches Array



  • Nunja, eigentlich passt das wirklich eher zu C... also wenn es jemand verschiebt... ich wäre nicht böse 😉

    knivil schrieb:

    Tut mir leid, aber diese Frage muss kommen: Warum?

    Einfach so, es geht mir ja eher um eine saubere Lösung, ich möchte wissen wie, die C++ Klassen machen das ja auch "irgendwie" und da ich mir ungerne den gesamten Sourcecode davon anschauen möchte...
    Also es geht mir im Grunde um das Wissen für eine schöne, saubere Lösung.

    Sone schrieb:

    Ich verstehe das nicht genau, erkläre mal was du damit meinst.

    Eben eine verlinkte Liste:

    struct whatever
    {
    int data;
    whatever* NextEntry;
    whatever* PrevEntry;
    }
    

    Sone schrieb:

    Machst du C oder C++? Ich höre malloc ; Und rate dir folgends, dir ein gutes Buch über C++ zu besorgen.

    Im Grunde mache ich C mit gewissem C++ "Syntax" (Bitte nicht schlagen!!) 😉
    malloc habe ich einfach nur als Bsp genannt, ich verwende eigentlich direkt HeapAlloc.
    Ein gutes C++ Buch? Habe ich eigentlich, wofür genau meinst du?

    Gruß!


  • Mod

    C und C++ wäre hier schon ein gewaltiger Unterschied. Die saubere Lösung in C++ wäre, vector (oder sonstwie passenden Container) nach zu programmieren. Vielleicht nicht mit allen Features (den Allokator und viele der selten genutzten Funktionen des Interfaces kann man erst einmal weglassen), aber schon mit den Grundzutaten:
    -Speicherverwaltung und Daten werden komplett von der Klasse gekapselt
    -Möglichst als Template
    -Zugriffe im STL-Stil
    Und natürlich mit den ganzen grundlegenden Designentscheidungen, die in C++ ohnehin Standard sind, wie zum Beispiel ein RAII-Design. Dazu gehört natürlich auch, dass die Elemente korrekt erstellt/kopiert/gemoved werden. Klingt komplizierter als es ist. In erster Linie heißt das aber vor allem, dass man kein rohes malloc/realloc benutzt.

    In C würde man es im Prinzip genau so machen, bloß dass man eben weder Klassen noch Templates hat, die einem helfen können und man daher alles von Hand machen muss. Was ziemlich viel Arbeit ist.



  • Designfrage schrieb:

    ..., wenn ein anderer Thread ebenfalls Speicher anfordert.

    Warum sollte das ein Problem sein?
    Solange der "andere" Thread seinen eigenen Speicher mit malloc/calloc/realloc reserviert und nicht denselben wie aus "deinem" Thread, hast du keine Probleme.
    (Mit Ausnahme, dass vielleicht nicht mehr genug freier Speicher für beide da ist).
    Verkettete Listen scheiden aus, da sich Performanz und verkettete Listen gegenseitig ausschließen.
    Nimm eine Kombination aus 1+3 und baue dir einen kleinen Speichermanager der
    zu Beginn einen "relativ" großen Speicher reserviert, wenn der im Programmablauf nicht mehr reicht, dann wachsende oder "relativ" konstant große Blöcke per realloc hinzufügen.
    Die Blockgrößen und/oder Wachstumsfaktoren solltest du konfigurierbar gestalten.



  • Vielen Dank erstmal für die vielen Antworten.

    SeppJ, tut mir wirklich leid, aber daraus werde ich nicht so wirklich schlau, könntest du den C-Ansatz vielleicht etwas auf mein Problem beziehen?

    Wutz schrieb:

    Warum sollte das ein Problem sein?
    Solange der "andere" Thread seinen eigenen Speicher mit malloc/calloc/realloc reserviert und nicht denselben wie aus "deinem" Thread, hast du keine Probleme.

    Seit wann hat jeder Thread seinen eigenen Heap? 😮

    Wutz schrieb:

    Nimm eine Kombination aus 1+3

    Habe ich im Moment auch so stehen, wirkt nur so... "suboptimal"...

    Gruß


  • Mod

    Designfrage schrieb:

    SeppJ, tut mir wirklich leid, aber daraus werde ich nicht so wirklich schlau, könntest du den C-Ansatz vielleicht etwas auf mein Problem beziehen?

    Objektorientierung kann man auch in C machen. Eine C++-Klasse ist nicht viel mehr als ein C-struct und ein paar Funktionen, die ein solches struct als Argument haben (der this-Zeiger). Das kannst du entsprechend auch in C machen, bloß musst du eben alles, was in C++ automatisch der Compiler macht (insbesondere Konstruktor- und Destruktoraufruf und eben die Übergabe des this-Zeigers) in C alles selber machen. Aber damit geht's dann im Prinzip genau so wie in Sprachen, die Objektorientierung von Haus aus können. Und ein Objektorientierter Ansatz bietet sich hier wirklich an.

    Aber wenn du ohnehin C++ machst, dann nutz doch Klassen! Das ist bloß Selbstschickane, sich da zu verweigern. Klassenunterstüztung auf Compilerebene ist einer der Gründe für die Erfindung von C++ gewesen.

    Wutz schrieb:

    Warum sollte das ein Problem sein?
    Solange der "andere" Thread seinen eigenen Speicher mit malloc/calloc/realloc reserviert und nicht denselben wie aus "deinem" Thread, hast du keine Probleme.

    Seit wann hat jeder Thread seinen eigenen Heap? 😮

    Gar nicht, aber malloc ist threadsicher*. Wo sollte also ein Problem sein?

    *: Zumindest mit den richtigen Compileroptionen. Es ist zwar nicht vom Standard garantiert, aber wenn malloc nicht threadsicher wäre, könntest du sämtliche Threadprogrammierung total vergessen. Daher ist auf Plattformen, die Threads können, mit Sicherheit auch ein threadsicheres malloc verfügbar.



  • Danke SeppJ, C/C++ kenn ich ja 😉
    Es geht mir nur darum, wie ich das o.g. Problem am "besten" lösen kann.

    Das malloc threadsicher ist, ist mir auch bekannt, da haben ich mich wohl zu unklar geäußert. Das Problem war eher auf mögliche Fragmentierung bezogen 🙂

    Gruß



  • Das Problem war eher auf mögliche Fragmentierung bezogen

    Hmmm....

    Meinst du jetzt Speicher Fragmentierung? Das ist Aufgabe des Betriebssystems. Nicht von dir.

    Ich glaube ich bin da ein wenig C geschädigt und habe deswegen Angst, dass du das Ganze machst, weil er performater, fehlerfreier,... sein sollte....

    Solange du das Ganze als Programmierübung ansiehst, ist dies aber ok. Ich würde hier anfangs auch mal die 2. Lösung nehmen.

    Und beschäftige dich mal später mit der Frage ob eine Funktion threadsicher ist. Dies ist nämlich nicht so trivial wie es auf den ersten Moment aussieht.

    PS:
    Warum willst du eigentlich HeapAlloc() nutzen und nicht malloc()?



  • Hey, tschuldigung, dass ich ich erst jetzt wieder antworte!

    Bitte ein Bit schrieb:

    Meinst du jetzt Speicher Fragmentierung? Das ist Aufgabe des Betriebssystems. Nicht von dir.

    Genau das meine ich. Klar ist das die Aufgabe vom Betriebssystem, aber man muss ja auch ein wenig "mithelfen". Ich meine folgendes Szenario:

    1. Thread 1: Meine Funktion läuft und vergrößert den Speicher ständig mit HeapReAlloc (oder was auch immer). Soweit so gut, wahrscheinlich wird die größe des bisher reservierten Blocks einfach erhöht.
    2. Thread 2: Dieser beginnt jetzt "gleichzeitig" damit, ebenfalls Speicher (HeapAlloc) anzufordern.
    3. Nun könnte doch folgende Situation auftreten. Speicherbelegung
    |...|Thread1_Buffer|Thread2_Buffer|
    So, wenn nun Thread1 wieder Realloc aufruft, kann der Block nicht einfach vergrößert werden, sondern muss verschoben werden, weil dahinter ja Thread2_Buffer liegt.
    A) |...|Thread1_Buffer|Thread2_Buffer|
    😎 |...|Lücke|Thread2_Buffer|Thread1_Buffer
    Hoffe das ist verständlich?

    Bitte ein Bit schrieb:

    Ich glaube ich bin da ein wenig C geschädigt und habe deswegen Angst, dass du das Ganze machst, weil er performater, fehlerfreier,... sein sollte....

    Also irgendwie ist die Angst schon berechtigt 🤡
    Naja, aber du hast schon recht, ist eher eine "Übung"... Die Sache ist, dass ich mir eine kleine Funktionsbibliothek bastel (für Windows/Linux) und da würde ein kleiner MemoryManager gut rein passen. Dass das Ganze nicht "optimal" wird, ist mir klar, damit kann ich aber leben, ist ja alles nur fürs Hobby 😉

    Bitte ein Bit schrieb:

    Und beschäftige dich mal später mit der Frage ob eine Funktion threadsicher ist.

    Sicher, wird beachtet, keine Frage, hatte nur hier für meine Frage eigentlich wenig Bedeutung.

    Bitte ein Bit schrieb:

    Warum willst du eigentlich HeapAlloc() nutzen und nicht malloc()?

    Och wofür? malloc ruft doch auch wieder HeapAlloc auf, da kann ich das doch direkt machen, und wie gesagt, das war auch eher beispielhaft genannt 😉

    Gruß!



  • Funktionsbibliothek bastel (für Windows/Linux)

    vs.

    malloc ruft doch auch wieder HeapAlloc auf

    🙄



  • @Designfrage
    Die Standardvariante sowas zu machen ist mit einem kleinen bis mittelgrossen Block anzufangen, und die Grösse dann immer um einen bestimmten Prozentsatz der aktuellen Puffergrösse zu vergrössern.
    Also z.B. einfach immer verdoppelt, oder mal 3/2 oder sowas.

    Und wieso willst du Dinge die bereits in der STL enthalten sind nachprogrammieren? Nur damit du es schlechter machen kannst?



  • knivil schrieb:

    Funktionsbibliothek bastel (für Windows/Linux)

    vs.

    malloc ruft doch auch wieder HeapAlloc auf

    🙄

    Für Windows HeapAlloc.
    Wobei ich noch einmal sage, dass das hier nur als Beispiel genommen wurde...

    hustbaer schrieb:

    Und wieso willst du Dinge die bereits in der STL enthalten sind nachprogrammieren? Nur damit du es schlechter machen kannst?

    Sagte ich auch schon. Ich mache es aus Spaß und habe absulut kein Anspruch, es besser bzw. perfekt zu machen 😉

    So, bevor es nun weitere Missverständnisse gibt... 🙂
    Danke euch für die Vorschläge zu meinem urspr. Problem, welches somit also gelöst wurde 👍


Anmelden zum Antworten