erstelle, befinden sich dann alle Matrizen auf dem Heap, oder muss ich
diese ebenfalls alle mit new allozieren?
Was ich auch immer nicht genau weiß. Wann macht es insgesamt Sinn
Speicher mit new zu allozieren und wann ist es besser Daten auf den
Stack zu packen? Gibt es da eine Faustregel oder so?
c_newbie schrieb:> Wann macht es insgesamt Sinn> Speicher mit new zu allozieren und wann ist es besser Daten auf den> Stack zu packen? Gibt es da eine Faustregel oder so?
Wenn die Objekte nicht mehr gebraucht werden sobald die Funktion
verlassen wird dann kannst Du sie auf den Stack packen.
Wenn sie länger leben sollen (z.B. weil Du zum Beispiel
Nachrichtenobjekte erzeugst und in eine Queue einreihst oder eine
verkettete Liste aus Objekten auufbaust wo sie dann längere Zeit
herumliegen sollen, auch nachdem die Funktion wieder verlassen wurde),
dann auf dem Heap.
Wenn Du von Anfang an genau weißt daß Du zum Beispiel genau 3 Instanzen
davon brauchst die von Anfang bis Ende Leben sollen dann kannst Du sie
auch einfach als globale Variablen anlegen.
Wenn Du auf nem kleinen Microcontroller mit knappem RAM unterwegs bist
macht es Sinn lange und hart nachzudenken wie man seine Daten so
organisieren kann daß man komplett auf das dynamische Allozieren von
Speicher zur Laufzeit verzichten kann.
c_newbie schrieb:> Wann macht es insgesamt Sinn> Speicher mit new zu allozieren
Immer dann, wenn du Daten bekommst, bei denen du vorher die Groesse
nicht kennst, z.B. wenn du den Inhalt einer Datei lesen willst.
Da weisst du ja beim Programmieren noch nicht, wie gross die Datei sein
wird, die du mal einlesen willst.
Natuerlich kannst du ein Array anlegen das x GB gross ist, dann solltest
du aber hoffen, dass die Datei nie groesser sein wird...
Ausserdem nutzt du so unnoetig Speicherplatz, den du vielleicht nie
brauchst. Also besorgt sich das Programm die Groesse der Datei und
allokiert soviel Speicher wie noetig.
Wenn du aber immer feste Daten(laengen) bekommst, dann kannst du einfach
z.B. ein Array anlegen mit x Elementen, da du nie weniger oder mehr
Speicher benoetigen wirst. Kein Grund fuer dynamische allokation.
>Wann macht es insgesamt Sinn>Speicher mit new zu allozieren und wann ist es besser Daten auf den>Stack zu packen?
Jo. Dynamisch Speicher allokiert man nicht - da stimmt was mit dem
Design nicht. Irgendwann stellst du dir die Frage nicht mehr, das ist
der Zeitpunkt an dem du dann auch dynamisch Speicher allokieren darfst.
gruß J
Kaj schrieb:> Immer dann, wenn du Daten bekommst, bei denen du vorher die Groesse> nicht kennst,
ich würde sagen das ist falsch.
Dann müssten man bei einem String ja immer new verwenden müssen.
c_newbie schrieb:> erstelle, befinden sich dann alle Matrizen auf dem Heap, oder muss ich> diese ebenfalls alle mit new allozieren?
Es wird so viel speicher angefordert, dass das Objekt da mit all seinen
Membern reinpasst.
Da du die Matrizen als Member und nicht als Pointer drin hast, ist deren
Speicherbedarf im Specherbedarf von Objekt enthalten.
Was die Matrizen selbst neben ihrer Objektstruktur noch an speicher
brauchen, müssen sie sich natürlich selbst in ihrem Konstruktor holen,
der bei Erzeugung deines Objektes natürlich mit aufgerufen wird.
jo schrieb:> Jo. Dynamisch Speicher allokiert man nicht - da stimmt was mit dem> Design nicht.
Diese Aussage ist in ihrer Pauschalität kompletter Unsinn. Es gibt
tausend Anwendungen bei denen erst zur Laufzeit bekannt werden wird
wieviele Instanzen eines Objekts man braucht oder wie groß irgendein ein
Array werden muss.
Peter II schrieb:> Dann müssten man bei einem String ja immer new verwenden müssen.
was meinst du denn, was in den meisten std::string-Operationen passiert?
>Diese Aussage ist in ihrer Pauschalität kompletter Unsinn. Es gibt>tausend Anwendungen bei denen erst zur Laufzeit bekannt werden wird>wieviele Instanzen eines Objekts man braucht oder wie groß irgendein ein>Array werden muss.
Du hast meine Aussage nicht verstanden, hab ich auch nicht erwartet. Und
stänkern tue ich auch gern. hahahahah
Gruß J
Vlad T. schrieb:> was meinst du denn, was in den meisten std::string-Operationen passiert?
es geht nicht warum was in dem Objekt passiert, sondern wo das objekt
angelegt wird.
Jede Variable braucht Speicher. So braucht ein "int" immer genug
Speicher um eine Zahl zu speichern, und ein "struct{int x;int y;}z;"
braucht genug Speicher um alle seine Member (also x und y) speichern zu
können. Auch Pointer brauchen Speicher, nähmlich genug Speicher um die
Adresse von auf was auch immer sie Zeigen speichern zu können. Wo das
ist worauf diese zeigen ist eine andere sache. Und natürlich auch ein
"int x[10];" genug speicher um 10 ints zu speichern. Wenn du jetzt ein
Struct oder eine Klasse als member eines Structs oder einer Klasse hast,
oder wirklich beliebige Datentypen, ist der Speicher der der diese
Felder benötigen ein teil vom Speicher welcher das Strukt benötigt, es
ist darin enthalten.
Es spielt also nur eine Rolle, was Matrix4 ist und tut. Wärend der
Speicher der Instanzen der Felder vom typ Matrix4 bei dir teil der
classe Objekt ist, und somit dort ist, wo auch immer die Instanz der
Klasse Objekt ist, kann Matrix4 durchaus ein Pointer sein, oder Pointer
enthalten, die dann sontwohin zeigen könnten. Ob Matrix4 einige Daten im
Heap ablegt und mit Pointern darauf zeigt, ist der Implementation der
Matrix4 überlassen.
Als Faustregel, ob man Objekte auf dem Stack oder Heap anlegen sollte,
würde ich sagen:
* Wenn man eine Variable nur innerhalb eines Scopes braucht (z.B.
innerhalb einer Funktion), und darauf keine externen referenzen/pointer
hat, dann auf dem Stack.
* Wenn die Anzahl zur Runtime variabel ist, dann auf dem Heap.
* Wenn man nur eine Referenz/Pointer hat, aber diese bei der
erstellenden Funktion zurückgiebt, dann auf dem Heap.
* Wenn man mehrere externe Referenzen/Pointer hat, dann auch auf dem
Heap, aber das free mittels std::shared erledigen lassen.
* etc.
Kaj schrieb:> c_newbie schrieb:>> Wann macht es insgesamt Sinn>> Speicher mit new zu allozieren> Immer dann, wenn du Daten bekommst, bei denen du vorher die Groesse> nicht kennst, z.B. wenn du den Inhalt einer Datei lesen willst.> Da weisst du ja beim Programmieren noch nicht, wie gross die Datei sein> wird, die du mal einlesen willst.
Ich kann aber die Größe der Datei vorher abfragen, jedes Betriebssystem
unterstützt das. Und ich kann z.B. nur einen Teil der Datei in den
Speicher einlesen. Es muss nicht unbedingt die ganze Datei auf einmal
sein. Zum Beispiel bei einer Logdatei interessieren mich vielleicht nur
die letzten zehn Einträge. Wenn sie nicht eh so eingerichtet ist, dass
sie zyklisch überschrieben wird und daher eine gewisse Größe gar nicht
überschreiten kann.
Und falls es kein Betriebssystem gibt, weil z.B. ein kleiner
Mikrocontroller "bare metal" programmiert, dann wäre es erst recht
seltsam wenn man es ständig mit beliebig großen Dateien zu tun hätte.
;-)
Peter II schrieb:> Vlad T. schrieb:>> was meinst du denn, was in den meisten std::string-Operationen passiert?>> es geht nicht warum was in dem Objekt passiert, sondern wo das objekt> angelegt wird.
Sorry, aber stellst du dich mit Absicht so dumm an?
Das Objekt wird da angelegt, wo du es deklarierst. Trotzdem holt es sich
intern natürlich Speicher vom Heap, um die Textdaten variabler Länge zu
managen.
Und wenn durch eine Operation die Länge des geholten Speichers
überschritten würde, wird vorher neu alloziert und kopiert.
Die Pufferverwaltung ist in der Regel aber so gelöst, dass nicht wegen
jedem zusätzlichen Zeichen neuer Speicher geholt und umkopiert werden
muss (es wird einfach mehr als benötigt geholt)
Vlad T. schrieb:> Sorry, aber stellst du dich mit Absicht so dumm an?
nein, wie kommst du darauf.
> Das Objekt wird da angelegt, wo du es deklarierst.
nein.
man kann es mit
string s* = new string();
oder mit
string s
anlegen. Dabei spielt es keine Rolle welche länge der String später hat.
Das war nur die Antwort auf den Kommentar von Kaj der behauptet das man
new immer dann verwendet wenn die länge nicht feststeht - und das stimmt
nicht.
Mark B. schrieb:> Ich kann aber die Größe der Datei vorher abfragen, jedes Betriebssystem> unterstützt das.
das kannst du aber nicht zur Compile-Zeit. Und wenn du es zur Laufzeit
machst, musst du genau dann entsprechend der Dateigröße dynamischen
Speicher allozieren. (es sei denn man legt vorher eine statischen,
maximale Häppchengröße fest und arbeitet mit dieser.
Peter II schrieb:> man kann es mit>> string s* = new string();
genau, hiers sagst du du willst es auf dem Heap
>> oder mit>> string s
und hier auf dem Stack (falls in nem lokalen scope)
Warum stimmt meine Aussage also nicht.
>> anlegen. Dabei spielt es keine Rolle welche länge der String später hat.> Das war nur die Antwort auf den Kommentar von Kaj der behauptet das man> new immer dann verwendet wenn die länge nicht feststeht - und das stimmt> nicht.
Kay ging es um die Implementierung. Und genau das macht std::string
auch. Er verwendet intern dynamischen (=Heap) Speicher, weil die Länge
des zu haltenden Textes zur Compilezeit von std::string noch nicht fest
stand.
Vlad T. schrieb:> das kannst du aber nicht zur Compile-Zeit. Und wenn du es zur Laufzeit> machst, musst du genau dann entsprechend der Dateigröße dynamischen> Speicher allozieren.
Seit wann denn das? Ich kann auch von einer fünf Megabyte großen Datei
nur die ersten einhundert Bytes einlesen, wenn ich lustig bin.
Mark B. schrieb:> Vlad T. schrieb:>> das kannst du aber nicht zur Compile-Zeit. Und wenn du es zur Laufzeit>> machst, musst du genau dann entsprechend der Dateigröße dynamischen>> Speicher allozieren.>> Seit wann denn das? Ich kann auch von einer fünf Megabyte großen Datei> nur die ersten einhundert Bytes einlesen, wenn ich lustig bin.
Und was machst Du wenn Du aus der Datei dann zum Beispiel nen Syntaxbaum
oder irgend ne andere Art von Graph oder sonstige Struktur aufbauen
willst, wo soll das gespeichert werden?
Bernd K. schrieb:> Mark B. schrieb:>> Vlad T. schrieb:>>> das kannst du aber nicht zur Compile-Zeit. Und wenn du es zur Laufzeit>>> machst, musst du genau dann entsprechend der Dateigröße dynamischen>>> Speicher allozieren.>>>> Seit wann denn das? Ich kann auch von einer fünf Megabyte großen Datei>> nur die ersten einhundert Bytes einlesen, wenn ich lustig bin.>> Und was machst Du wenn Du aus der Datei dann zum Beispiel nen Syntaxbaum> oder irgend ne andere Art von Graph oder sonstige Struktur aufbauen> willst, wo soll das gespeichert werden?
Meine Antwort war dazu gedacht, die Aussage von Kaj (Gast) zu
wiederlegen:
> Immer dann, wenn du Daten bekommst, bei denen du vorher die Groesse> nicht kennst, z.B. wenn du den Inhalt einer Datei lesen willst.> Da weisst du ja beim Programmieren noch nicht, wie gross die Datei sein> wird, die du mal einlesen willst.
"Immer" bzw. das Beispiel stimmt so pauschal eben nicht.
Natürlich hast Du Recht, dass es viele Anwendungsfälle gibt, bei denen
es so ist wie oben beschrieben. Nur eben nicht immer.
Mark B. schrieb:> "Immer" bzw. das Beispiel stimmt so pauschal eben nicht.>> Natürlich hast Du Recht, dass es viele Anwendungsfälle gibt, bei denen> es so ist wie oben beschrieben. Nur eben nicht immer.
Entweder du weisst wie gross deine Daten sind oder nicht.
Du willst x Byte lesen? Dann weisst du die Groesse doch.
Mark B. schrieb:> Meine Antwort war dazu gedacht, die Aussage von Kaj (Gast) zu> wiederlegen:
Sorry, aber wiederlegt hast du gar nichts.
Ich schrieb "Immer dann, wenn du [...] die Groesse nicht kennst..."
und du kommst mit "wenn ich eine feste groesse lesen will"...
Tschuldigung, aber auf dein Trollniveau geh ich gar nicht weiter ein.
c_newbie schrieb:> wenn ich jetzt ein Objekt über> objekt1 = new Objekt(param);> erstelle, befinden sich dann alle Matrizen auf dem Heap, oder muss ich> diese ebenfalls alle mit new allozieren?
Also, wenn die Klasse richtig (weniger dogmatisch gesagt: vernünftig)
implementiert ist, dann brauchst du dir die Frage nicht stellen; du
wirst nichts weiter tun müssen. Es ist Aufgabe des Konstruktors der
Klasse, die Matrizen geeignet zu initialisieren.
c_newbie schrieb:> Wann macht es insgesamt Sinn> Speicher mit new zu allozieren und wann ist es besser Daten auf den> Stack zu packen? Gibt es da eine Faustregel oder so?
Faustregel: Wenn die Objekte "Werte" repräsentieren, dann kann man sie
auf dem Stack anlegen; wenn die Objekte eine "Identität" besitzen, dann
muss man sie besser auf dem Heap anlagen.
Was heißt das nun? Viele Objekte repräsentieren nur "Werte", z.B., ein
int, ein String, eine Matrix. Werte können beliebig kopiert werden und
man kann die Kopien unabhängig voneinander verändern. Der Code wird also
üblicherweise so aussehen:
1
intdim=5;
2
std::stringtext="abc";
3
Matrixm(dim);
aber nie so:
1
int*dim=newint(5);
2
std::string*text=newstd::string("abc");
3
Matrix*m=newMatrix(*dim);
Objekte besitzen eine "Identität", wenn es keinen Sinn macht, die
Objekte zu kopieren. Wenn dein Objekt z.B. ein Fenster auf dem Desktop
repräsentiert, dann hat es eine Identität. Ein Fenster wie eine Zahl
oder einen String zu kopieren macht keinen Sinn. Dann wird man eher
1
Window*wnd=newWindow;
schreiben. Ab dann muss man sich aber auch Gedanken machen, wer für das
so allozierte Objekt zuständig ist und wer es freigeben muss. Weitere
Beispiele für Objekte mit Identität sind Spieler in einem Spiel, eine
Datei, eine Datenbanktabelle.
Kaj schrieb:> Mark B. schrieb:>> "Immer" bzw. das Beispiel stimmt so pauschal eben nicht.>>>> Natürlich hast Du Recht, dass es viele Anwendungsfälle gibt, bei denen>> es so ist wie oben beschrieben. Nur eben nicht immer.> Entweder du weisst wie gross deine Daten sind oder nicht.> Du willst x Byte lesen? Dann weisst du die Groesse doch.
Was Du übersiehst: Man kann sukzessive Blöcke einer festen Größe lesen,
um am Ende eine Datei von beliebiger Länge abzuarbeiten. Genau so machen
es zum Beispiel MP3-Player oder DVD-Player. Die Datei muss zum Abspielen
nicht komplett in den Hauptspeicher geladen werden, es reicht ein Teil
davon. Es wäre sonst auch ziemlich schwierig, Audio- oder Videodateien
mit mehreren Stunden Länge abzuspielen. Es besteht also in diesen Fällen
keine zwingende Notwendigkeit dafür, dynamisch Speicher zu allokieren.
Nichtsdestotrotz kann die Datei eine beliebige Länge haben, die zur
Übersetzungszeit nicht bekannt ist.
Natürlich gibt es auch etliche Anwendungsfälle, in denen man eine Datei
komplett einlesen muss. Zum Beispiel wenn man ein Foto auf dem
Bildschirm darstellen will. Das ändert aber nichts daran, dass Deine
Aussage von weiter oben nicht für alle Anwendungsfälle gilt.
> Mark B. schrieb:>> Meine Antwort war dazu gedacht, die Aussage von Kaj (Gast) zu>> wiederlegen:> Sorry, aber wiederlegt hast du gar nichts.>> Ich schrieb "Immer dann, wenn du [...] die Groesse nicht kennst..."> und du kommst mit "wenn ich eine feste groesse lesen will"...>> Tschuldigung, aber auf dein Trollniveau geh ich gar nicht weiter ein.
Fähige Leute tauschen Argumente auf sachlicher Ebene aus. Ich habe Dir
ein gültiges Gegenbeispiel genannt, das Deine Aussage widerlegt. Nun
kehre bitte auch wieder auf die sachliche Ebene zurück. Vielen Dank.
Mark B. schrieb:> Kaj schrieb:>> Mark B. schrieb:>>> "Immer" bzw. das Beispiel stimmt so pauschal eben nicht.>>>>>> Natürlich hast Du Recht, dass es viele Anwendungsfälle gibt, bei denen>>> es so ist wie oben beschrieben. Nur eben nicht immer.>> Entweder du weisst wie gross deine Daten sind oder nicht.>> Du willst x Byte lesen? Dann weisst du die Groesse doch.>> Was Du übersiehst: Man kann sukzessive Blöcke einer festen Größe lesen,> um am Ende eine Datei von beliebiger Länge abzuarbeiten.
Aber dann weißt du, wie groß die Daten sind, die du lesen willst.
Kaj schrieb:> Immer dann, wenn du Daten bekommst, bei denen du vorher die Groesse> nicht kennst,
Wenn du aus der Datei 1000 Bytes liest und diese 1000 fest im Quellcode
eingetragen hast, weißt du zur Compilezeit, dass (maximal) 1000 Bytes
kommen, also kennst die Größe doch. Laut Kaj brauchst du dafür also
keinen dynamischen Speicher.
Rolf M. schrieb:> Mark B. schrieb:>> Kaj schrieb:>>> Mark B. schrieb:>>>> "Immer" bzw. das Beispiel stimmt so pauschal eben nicht.>>>>>>>> Natürlich hast Du Recht, dass es viele Anwendungsfälle gibt, bei denen>>>> es so ist wie oben beschrieben. Nur eben nicht immer.>>> Entweder du weisst wie gross deine Daten sind oder nicht.>>> Du willst x Byte lesen? Dann weisst du die Groesse doch.>>>> Was Du übersiehst: Man kann sukzessive Blöcke einer festen Größe lesen,>> um am Ende eine Datei von beliebiger Länge abzuarbeiten.>> Aber dann weißt du, wie groß die Daten sind, die du lesen willst.
Jein. Ich kenne dann die Größe eines zu bearbeitenden Teils, aber nicht
die Gesamtgröße.
Vielleicht reden wir hier auch aneinander vorbei. Die Aussage war ja:
Kaj schrieb:> Immer dann, wenn du Daten bekommst, bei denen du vorher die Groesse> nicht kennst, z.B. wenn du den Inhalt einer Datei lesen willst.
Wovon der erste Teil richtig ist, aber das Beispiel passt so nicht weil
es wie beschrieben Gegenbeispiele gibt.
Vlad T. schrieb:> c_newbie schrieb:>> erstelle, befinden sich dann alle Matrizen auf dem Heap, oder muss ich>> diese ebenfalls alle mit new allozieren?>> Es wird so viel speicher angefordert, dass das Objekt da mit all seinen> Membern reinpasst.>> Da du die Matrizen als Member und nicht als Pointer drin hast,
Das ist nicht sicher, da die Typ-definition von Matrix4 nicht bekannt
ist.
Vielleicht ist es definiert als ein pointer auf einem Struct.
Eric B. schrieb:> Das ist nicht sicher, da die Typ-definition von Matrix4 nicht bekannt> ist.> Vielleicht ist es definiert als ein pointer auf einem Struct.
dann hat er es nicht anders verdient *diabolisch lach*