Was bringt der Heap



  • Hallo
    Ic hba e vor einiger Zeit mit programieren anfegangen und jetzt bin ich bei Zeigern angelangt. Es geht darum Speicher im Heap zu resevieren???? Mit new erzegut man diesen Speicher
    bsp.

    unsinged short int *pZeiger;
    pZeiger = new usnigned short int;
    

    Aber ich verstehe nicht was erstmal Zeiger überhaupt für einen SInn haben und was bringt dieser Heap oder Stack?



  • Heap und Stack sind nicht das selbe!
    Auf dem Stack werden Variablen, Rückkehradressen und weiteres Klumb temporär abgelegt, wenn du eine Funktion aufrufst.

    Mit new erzeugte Objekte bleiben im Speicher (theoretisch sogar auch noch, wenn dein Programm beendet ist), und du musst sie manuell mit delete löschen.

    Der Vorteil von Zeigern ist, dass wenn du einer Funktion ein Objekt übergeben willst, was mehrere kb groß ist, kannst du stattdessen einen Zeiger auf das Objekt übergeben, der ist nur 4Byte groß.

    new und delete braucht man in der Praxis relativ selten, ich hab es eigentlich nur für meine String-Klasse gebraucht. Arbeite lieber mit globalen Variablen wo nötig und mit lokalen Variablen (die auf dem Stack liegen), wenn möglich.

    Mein Tipp: Setze dich erstmal mit Zeigern, Referenzen und Arrays auseinander, dann kannst du dich mit den Speicherbereichen befassen.



  • ist zwar für C, sollte dir aber trotzdem helfen Pointer zu verstehen

    http://pw1.netcom.com/~tjensen/ptr/pointers.htm



  • Optimizer schrieb:

    new und delete braucht man in der Praxis relativ selten, ich hab es eigentlich nur für meine String-Klasse gebraucht.

    Huh, darf man fragen was du programmierst? Ich habe in meinem aktuellen Projekt unzählige Stellen an denen ich dynamischen Speicher anfordere.

    Optimizer schrieb:

    Arbeite lieber mit globalen Variablen...

    Also wenn das ein Ratschlag sein soll dann ist er *sry* ABSOLUTER BULLSHIT!

    Optimizer schrieb:

    Der Vorteil von Zeigern ist, dass wenn du einer Funktion ein Objekt übergeben willst, was mehrere kb groß ist, kannst du stattdessen einen Zeiger auf das Objekt übergeben, der ist nur 4Byte groß.

    Man sollte hier vielleicht noch die Referenz erwähnen. Die ist in solchen fällen nämlich freundlicher als ein Pointer, weil man sicher sein kann, dass sie nicht ins Nirvana zeigt.



  • Optimizer schrieb:

    Der Vorteil von Zeigern ist, dass wenn du einer Funktion ein Objekt übergeben willst, was mehrere kb groß ist, kannst du stattdessen einen Zeiger auf das Objekt übergeben, der ist nur 4Byte groß.

    Das ist der (bzw. ein) Vorteil von Referenzen, nicht nur von Zeigern. Zeiger kann man dafür übergeben, wenn ein Parameter optional sein soll, weil Zeiger im Gegensatz zu Referenzen 0 sein können.

    Und Zeiger braucht man um Arrays zu untersuchen, auf bereits erstellte Objekte zu zeigen ohne neue zu erstellen, um Objekte über einen {}-Block hinaus am Leben zu erhalten, um Strukturen von variabler Größe (Strings, Container) zu implementieren...



  • Optimizer schrieb:

    new und delete braucht man in der Praxis relativ selten

    Hm, new ist IMHO schon relativ häufig in normalem Code, und dass man Zeiger und new/delete versteht würde ich deshalb auch wichtig nennen (Arrays und new[]/delete[] nicht unbedingt). Ich finde zwar, dass delete außerhalb von Wrapperklassen (also direkt im Anwendungscode) nichts zu suchen hat, aber verstanden haben muss man's trotzdem, um man die richtige Wrapperklasse auszusuchen.



  • MaSTaH schrieb:

    Huh, darf man fragen was du programmierst? Ich habe in meinem aktuellen Projekt unzählige Stellen an denen ich dynamischen Speicher anfordere.

    Ja, das hängt wohl sicherlich vom Projekt ab. ICH brauche new selten und als Anfänger braucht man es noch seltener.

    MaSTaH, ich lade dich hiermit ein, genauer zu lesen!! 🙄

    1. "Arbeite lieber mit globalen Variablen wo nötig und mit lokalen Variablen (die auf dem Stack liegen), wenn möglich."
    Das "lieber" bezieht sich natürlich darauf, dass wenn man Speicher nicht dynamisch anfordern muss, dass man dann lieber auf das new verzichtet und eine globale oder lokale Variable verwendet.

    2. "Setz dich erstmal mit Zeigern, Referenzen..."
    Ich weiß selber, dass man im Zweifelsfall Referenzen verwenden sollte, aber er wollte etwas über Zeiger wissen.



  • operator void schrieb:

    Optimizer schrieb:

    new und delete braucht man in der Praxis relativ selten

    Hm, new ist IMHO schon relativ häufig in normalem Code, und dass man Zeiger und new/delete versteht würde ich deshalb auch wichtig nennen (Arrays und new[]/delete[] nicht unbedingt). Ich finde zwar, dass delete außerhalb von Wrapperklassen (also direkt im Anwendungscode) nichts zu suchen hat, aber verstanden haben muss man's trotzdem, um man die richtige Wrapperklasse auszusuchen.

    Ich habe deshalb arrays erwähnt, weil ein Array auch ein Zeiger (auf das erste Element) ist und nicht wegen delete[].



  • Optimizer schrieb:

    MaSTaH, ich lade dich hiermit ein, genauer zu lesen!! 🙄

    Ich habs jetzt nochmal gelesen und befinde es immer noch für Bullshit.

    Optimizer schrieb:

    Arbeite lieber mit globalen Variablen wo nötig

    Durch das "wo nötig" wird es auch nicht besser was du sagst. Du sagst man sollte lieber globale Variablen benutzen. Entweder man muss eine globale benutzen (was IMHO in 90% aller Fälle vermieden werden kann) oder man kann die Aufgabe komplett anders erledigen und braucht nichts globales. Globale Variablen können in der Tat Sinn machen, sind aber gerade einem Anfänger nicht ans Herz zu legen, da sonst Programme in der folgenden Art entstehen:

    #include <iostream>
    
    int x = 0;
    
    void eingabe() {
      std::cin >> eingabe;
    }
    
    void ausgabe() {
      std::cout << eingabe;
    }
    
    int main() {
      eingabe();
      ausgabe();
    }
    

    Und sowas ist schlicht und einfach scheiße. Wir sind zu faul Parameter zu übergeben. Wieso auch? Ist doch alles bequem und global 🙄 .



  • Sorry, das langweilt mich einfach. Du liest meinen Post nicht mal vernünftig durch und führst dich dann auf.

    Durch das "wo nötig" wird es sehr wohl besser, es heißt nämlich genau das, was du mit den Parametern gesagt hast, dass man globale Variablen nur verwenden sollte wo es nötig ist.
    Und Referenzen habe ich ausdrücklich erwähnt, obwohl der Threadersteller nicht mal danach gefragt hat.

    Entschuldigung, dass ich ihm den Tipp gegeben habe, erstmal globale Variablen und lokale Variablen (Stack) zu verstehen, bevor er mit dem Heap arbeitet. Ich kann mir nicht vorstellen, dass er jetzt unbedingt dynamisch Speicher anfordern muss, wenn er so unwissend fragt.

    Echt krass, du gehst ab wie ein Zapferl. Und das ist nicht das erste mal, dass du mich dumm von der Seite anmachst.



  • Also ehrlich .... wer programme schreibt, die kaum new oder delete verwenden ... warum nimmt er dann C++ ? Das geht doch mit anderen Programmiersprachen dann genau so gut :p
    Ok, wenn man soweiso c++ kann, dann schreibt man aber auch das typische "Hallo World" programm in C++ ; Viele Standard klassen nehmen einem das auch ab, so das man nicht unbedingt selber speicher mit new und delete anfordern muss, trotz das man zur compile zeit ned weiss, wieviel man braucht. Auch schaetz ich mal, das 99% aller c++ programme Heap speicher anfordern :p

    Aber spaetestens wenns um Polymorphie geht, braucht mans dann doch ...

    Ciao ....



  • polymorphie? heap? komm da jetzt nicht ganz mit...

    btw. so aussagen wie

    ABSOLUTER BULLSHIT!

    und

    Echt krass, du gehst ab wie ein Zapferl.

    könnt ihr gerne in einem anderen forum fortsetzen, hier bitte sachlich bleiben, und wenn man kritik ausübt, dann in einer gemäßigten sprache.



  • Manco schrieb:

    ich verstehe nicht was erstmal Zeiger überhaupt für einen SInn haben

    ich hoffe, du hast genügend antworten bekommen. wenn nicht, dann google mal nach, oder warte, bist du mehr über sie lernst. am anfang kommt man tatsächlich oft nicht drauf, wozu zeiger.

    Manco schrieb:

    und was bringt dieser Heap oder Stack?

    Heap ist nicht gleich Stack. Probier mal folgendes:

    int main () {
       int i[100000000]; //viel platz am stack
       int *pi = new int[100000000]; //viel platz am heap
    
       int size;
       cin >> size;
       int stacke[size]; //klappt nicht: die größe muss zur kompilierzeit bekannt sein
       int *heap = new int[size]; //klappt
    
       delete [] pi; //dafür muss man den speicher auch wieder freigeben
       delete [] heap; 
    }
    

    das sind so die wichtigsten unterschiede. probier das mal aus, dann kommst du vielleicht dahinter 🙂



  • polymorphie? heap? komm da jetzt nicht ganz mit...

    Naja, polymorphie geht halt nur mit Zeigern.
    Meist erzeugt man polymorphe Objecte in Klassenfabriken, also Objecte, denen man "irgenwie" sagt, was man braucht, und die erzuegen einem ein spezielles Object (per new) geben einem aber nen zeiger auf ne basisklasse zurueck (und haben dann nie wieder was mit dem ding zu tun) .

    Klar, koennt man die Objecte auch aufn Stack erzeugen, und die Zeiger per adress operator erzeugen ... , aber wenn man sein programm designmaessig in viele module gliedert, wird man kaum nen modul finden, was lange genug lebt, um lieferant fuer so nen zeiger zu sein ... das ueberlebt dann halt nur nen dynamisches Object, also aufn heap ...

    Ciao ...



  • RHBaum schrieb:

    Naja, polymorphie geht halt nur mit Zeigern.

    Mit Referenzen geht es genauso.
    Und ich benutze Objekte am Stack durchaus des öfteren Polymorph.



  • Ja, klar ich auch 😃
    ich dereferenzier auch zeiger, und geb sie als Referenz weiter, auch polymorph, aber doch eher selten 🙂
    Ist vielleicnt gaengiges, aber bestimmt nicht das haeufigste vorgehen, und man muss auch wissen was man tut ! 😃
    Wenn man will kann man alles. Auch dynamisch Speicher anfordern ohne "heap" zu benutzen. Nur die frage nach dem sinn bleibt immer noch ... Und ich denk mal, darum gehts hier auch ned :p Ich glaub unsere Beitraege verwirren ihn nur.

    Wichtig fuer Manco sind eher die Konsequenzen ...

    Am Beispiel fuer nen String

    // 1. speicher aufn Stack
    char mystring[100];

    // 2. speicher dynamisch
    char * mystring = new char[100];

    wichtig zu wissen ...
    die gemeinsamkeiten:
    mystring ist beides mal nen Zeiger. weil, wie wir wissen, eine arrayvariable (1.) immer die addresse des ersten elementes darstellt. also ists sowas wie zeiger, und kann als solcher benutzt werden.
    einmal nen speicher angelegt, kann dessen groesse ned veraendert werden. egal ob aufn stack oder aufm heap, willst die groesse aendern, musst das alte wegwerfen. nur bei 1. gehts halt ned auf commando. 🙂 bei 2. schon und man kann die zeigervariable wiederverwenden (aber ned den speicher)

    die unterschiede:
    Geschwindigkeit: 1. ist ne menge schneller als 2.
    Scope: dein dynamischer Speicher(2) haelt solange bis du es zerstoerst. (delete[] mystring).
    Der stack und damit version(1) haelt nur solange, wie der scope ist, also bis den funktionsblock verlaesst, wo das teil drinnen deklariert hast. gehst da raus, wird es zertoert - automatisch (musst dich selbst also nicht kuemmern). Hast noch nen zeiger anderswo drauf und bentuzt ihn danach, fuehrt das meisst zu undefienierten verhalten. Dafuer muesst aber bei der dynamischen version den speicher expliziet wieder freigeben, und darfst den zeiger niemals verbummeln, sonst gibts Memory leaks.
    Dynamic:
    bei version 1 muss die groesse feststehen, zur Compilezeit ... bei version 2 langts zur laufzeit !

    size_t isize = 100;
    char mychar[isize];
    
    size_t isize = 100;
    char * mychar = new char[isize];
    

    Versuch mal beides zu compilieren ....
    Bindung der Variable:
    bei 1. wird deine Variable immer auf das vorgegebene Array(speicher) zeigen, ist also konstant, (sprich die Adresse auf die mystring zeigt, wird sich nie anedern = constant) bei 2. kannst den zeiger auch woanders hin zeigen lassen ...

    size_t isize = 100;
    char * mychar = new char[isize]; 
    delete[] mychar; 
    mychar = new char[isize * 2];
    

    das geht hingegen ohne probleme ... nur muss man aufpassen, das man keine leaks hinterlaesst.

    Du siehst, beides hat Vor und Nachteile, und eigentlich nen unterschiedliches anwednungsgebiet, wobei sich einige bereiche doch an und ab ueberschneiden.

    fuer einfachere sachen braucht man meist die Version aufn Stack ... die isst schneller, sicherer (durch automatische speicherfreigabe) ... dafuer viel unflexiebler (keine dynamische groesse)

    die version aufn heap braucht man sofort, wenn es um dynamische Groessen geht. Meist wird einem aber gerade das von den Bibliotheken (STL siehe vector map ... etc) abgenommen, wenn man das erste mal auf das Problem stoesst 🙂

    Als Ubeung kannst ja mal nen programm schreiben, was einen Speicher fuer X elemente reserviert, wobei X vom User anzugeben ist (per Abfrage). Und du darfst dabei keine Zeiger (kein new / delete, kein malloc, free und keine API-Aufrufe, die Speicher anfordern), und keine Containerklassen aus diversen biblotheken verwenden ... auch darfst nicht auf verdacht den maximal moglichen Speicherblock allocieren und nur den benoetigen anteil daraus freizugeben ....

    Viel SPass ! 😃

    Ciao ...



  • Warum man noch Speicherreservierung braucht.

    Verwaltet man Datenstrukturen die sehr groß sind kommt man schnell an die Grenze des Stack da viele Kopiler diesen auf 1 MB setzen.
    Der Heap ist begrenzt dur den Spiecher welcher sich im Rechner befindet.
    Klar kann man den Stack auch erhöhen. Aber warum sollte man dies tun auser wenn man viele Rekursionen oder ähnliches hat, bei denen sich die Standardgröße des Stack auch nicht ausgeht.
    In meiner ganzen Zeit als Programmierer > 15 Jahre bin ich eigentlich noch nie soweit gewesen in C++ globale Variablen zu verwenden.



  • Optimizer schrieb:

    Echt krass, du gehst ab wie ein Zapferl. Und das ist nicht das erste mal, dass du mich dumm von der Seite anmachst.

    Ach nein, wann denn noch? Wenn du so etwas als dumme Anmache verstehst dann tust du mir leid. Den "Bullshit" nehme ich zurück wenn du dich dadurch verletzt gefühlt hast. Aber dein Posting kam so in etwa rüber: "Dynamischen Speicher braucht man nicht wirklich. Wenn nötig kannst du ja auch ein globales Objekt nehmen." Wenn ich dich da absolut falsch interpretiert habe dann entschuldige ich mich hiermit.



  • RHBaum schrieb:

    Also ehrlich .... wer programme schreibt, die kaum new oder delete verwenden ... warum nimmt er dann C++ ? Das geht doch mit anderen Programmiersprachen dann genau so gut :p

    Kannst du diese Aussage irgendwie erklären? In C++ kann man viele Dinge völlig ohne new und delete lösen, für die man in anderen Sprachen schon den Zeiger-Hammer rausholen müsste.
    Und wenn du mit "delete verwenden" meinst, dass in normalem Programmcode "delete" verwendet wird, dann ist die Aussage IMHO noch um einiges fragwürdiger, weil C++ gerade eine der wenigen Sprachen ist, die einem das elegant abnimmt.



  • Kannst du diese Aussage irgendwie erklären?

    Was ich meine ist:
    wenn man new und delete absichtlich umgeht ... aus irgendwelchen Gruenden, die nicht rein programmiertechnischer Natur sind ... sollt man vielleicht ne Programmiersprache waehlen, die einem da mehr Comfort bietet. "Garbage collections" usw. (ja die verwenden auch HEAP aber der user muss sich damit ned rumschlagen)
    Sicher sind die autoptr klassen, string klassen und Container elegant, aber wenn man sich halt mit Zeiger ned beschaeftigen will, fliegt man auch mit denen irgendwann auf die Nase, und zwar kraeftig.

    Das schoene an C++ ist ja, dass man so "systemnah" ist, und man mit pointer manipulieren kann, auf ganz boese "art". 😉
    Wenn wer aber C++ lernt nur um mittels STL container standard operationen auf filestreams und auf standard ein/ausgabe zu schreiben, der "verpasst" viel von der Sprache, der haette es mit ner anderen sprache sicher leichter.
    Mit Klassenbiblotheken kommt er dann um zeiger meist nimmer drumherum.
    Und mal ehrlich, wieviel % der ernsthaften C++ programme verwenden keine klassenbiblio oder C-API ? "Hallo world" Programme schreib ich in Basic schneller ! ok, uber die Ethik laesst sich da streiten !!! 🙂
    Wenn aber nen ambitionierter Neueinsteiger mit Pointer ned so klarkommt, sollt man ihm ned sagen, dass er die ja gar ned unbedingt braucht, sondern ihm eher die Angst vor nehmen, und zeigen, was er damit fuer Vorteile gegenueber anderen Programmiersprachen denn hat.
    Sonst endet er irgendwo in der Kategorie der CT Redaktuere, die den Artikel ueber den Performance vergleich C++, Pascal, C# Java ... geschrieben haben.

    Das meint ich damit !

    Ciao ...


Anmelden zum Antworten