Theoretische Frage delete



  • 1000*sizeof(was_weiss_ich)



  • Verwende std::vector.

    Und zu deiner Frage: es geht einfach konzeptionell nicht. Ein Pointer hat einfach keine Länge, das passt nicht ins Konzept. Ein Pointer ist einfach eine Speicheradresse, Punkt aus. Er könnte ja schließlich auch mitten ins Array hineinzeigen - wie soll man dann jemals auf die richtige Länge kommen?



  • struct test {
    	int a[4];
    	double d[2];
    	};
    
    int main()
    	{
    	test *ptr=new test[10];
             cout<<(sizeof*ptr*sizeof test);
    	delete [] ptr;	
    	return 0;
    	};
    


  • Was soll das darstellen?



  • MisterX schrieb:

    Der Compile weiss, wieviel dort allociert wurde.

    naja, eigentlich weiß er es nicht. oder doch? ka. ist nicht definiert. ok, er weiß es offentichtlich, wenn er nichttriviale destruktoren aufrufen muß. aber bei pods? nee, da muß er es nicht wissen und ich hoffe mal, er schreibt es auch nirgends hin. bei delete[] muß er nicht die genau anzahl kennen, sondern muß´nur den speicher wegmachen. im falle eines binary buddy allocators wäre das die nächsthöhere zweierpotenz und die genau größeninfo der nutzdaten wüßte keiner.

    Nun meine Frage dazu: Warum gibt es denn nicht sowas wie t.length() wie in java?

    wieß nicht. vielleicht wegen speed. vielleicht wurde es auch einfach vergessen.

    Da ich von java umgestiegen bin ist es wirklich konzeptionell schwierig sich daran zu gewöhnen immer eine Variable mitschleppen zu müssen, die die maximallänge des Arrays angibt!

    benutz einfach vector<int> a; statt int* a=new int[10]; und du hast size() als methode. denk dran, den vector als referenz zu übergeben, weil das scheller ist.



  • So erfährt delete wieviel Speicher er freigeben muss:

    Also,...
    Wenn du mit new Speicher anforderst wird ein Speicherblock für dich bereitgestellt der so aussieht...

    |---------------------|
    |Daten über die Größe |
    | des Speicherblocks  |
    |---------------------|
    |    Dein Speicher    |
    |                     |
    |---------------------|
    

    Das heißt das du nicht nur Speicher für dein Objekt/Datentyp anforderst, sondern das vor diesen Speicherbereich noch Infos über die Größe des Speichers für operator delete stehen 😉

    Somit weiß delete wieviel er löschen muss 👍



  • volkard schrieb:

    ok, er weiß es offentichtlich, wenn er nichttriviale destruktoren aufrufen muß. aber bei pods? nee, da muß er es nicht wissen und ich hoffe mal, er schreibt es auch nirgends hin. bei delete[] muß er nicht die genau anzahl kennen, sondern muß´nur den speicher wegmachen.

    Das geht aber schlecht, wenn er eben nicht genau weiß wieviel. Es gibt doch die Variante von operator delete mit dem size Parameter. Da kann er dir immer die richtige Anzahl reingeben, er weiß es also sehr wohl.



  • Ringding schrieb:

    Und zu deiner Frage: es geht einfach konzeptionell nicht. Ein Pointer hat einfach keine Länge, das passt nicht ins Konzept. Ein Pointer ist einfach eine Speicheradresse, Punkt aus. Er könnte ja schließlich auch mitten ins Array hineinzeigen - wie soll man dann jemals auf die richtige Länge kommen?

    Das ist so nicht ganz richtig. Der C++ Standard legt nicht fest, wie ein Zeiger intern aufgebaut ist, d.h. es muss sich nicht zwingend um eine Speicheradresse handeln, auch wenn es oft so ist.

    Eine virtuelle Maschine z.B. koennte einen Zeiger aus Selektor:Offset bilden, und bei jedem Zugriff auf den Zeiger den Selektor in einer Tabelle nachschauen, Speicheradresse und Laenge des Speicherblocks ermitteln und dann z.B. Bereichspruefungen machen. So ein aehnliches Konzept gab es auch m.W. in MULTICS. Auf so einem System waere eine Spracherweiterung denkbar, mit der man die Groesse eines Speicherblocks auch nachtraeglich noch ermitteln konnte.

    Viele Speicherverwaltungsroutinen merken sich intern auch die Groesse eines Speicherblocks, um ihn hinterher wieder freigeben zu koennen.

    Wenn man das Feature in C++ unbedingt haben will, braucht man nur neue globale new- und delete-Operatoren zu schreiben, die jedem Speicherblock grundsaetzlich eine Laenge voran stellen, die man dann mittels einer weiteren Funktion abfragen kann.



  • Dann weißt du aber immer noch nicht, wo der Speicherblock beginnt. Du müsstest eine Tabelle (Hash Table z.B.) von sämtlichen Speicherblöcken mitführen, damit du immer weißt, in welchen Speicherblock ein bestimmter Pointer gerade zeigt - wie ich geschrieben habe, muss er ja nicht unbedingt an den Anfang eines Blocks zeigen. Er kann sogar ins Nirvana zeigen, solange er nicht dereferenziert wird.



  • Wenn Du ein new[] gemacht hast, und jetzt ein delete[] irgendwo mitten in den Speicherbereich machst, bringt das den Standardallokator mächtig durcheinander und gibt undefiniertes Verhalten. Der Pointer muss immmer an den Anfang des Blocks zeigen, wenn Du delete aufrufst. Smarte Implementierungen oder DebugTools können das erkennen und abfangen - zulässig ist das aber nicht.



  • Ringding schrieb:

    Dann weißt du aber immer noch nicht, wo der Speicherblock beginnt. Du müsstest eine Tabelle (Hash Table z.B.) von sämtlichen Speicherblöcken mitführen, damit du immer weißt, in welchen Speicherblock ein bestimmter Pointer gerade zeigt - wie ich geschrieben habe, muss er ja nicht unbedingt an den Anfang eines Blocks zeigen. Er kann sogar ins Nirvana zeigen, solange er nicht dereferenziert wird.

    Intel 80x86 (auch Pentium) Prozessoren machen das genauso (z.B. im 32-Bit Protected Mode): Der Selektor ist ein Index in die Speicher-Deskriptortabelle und der Offset gibt den relativen Versatz der Adresse an. Du siehst, das geht also sehr wohl.

    Im Flat Speichermodell sind die Selektoren vom Betriebssystem vorgegeben, aber es gibt auch unter Windows XP und Linux far pointer, die mit Selektor:Offset arbeiten (48 Bit).

    Ueber den Offset-Teil addressiert Du die Position relativ zum Speicherblock, der durch den Selektor adressiert wird.

    // char* p = new char [2]; vorausgesetzt
    p[0] = 'A';
    p[1] = 'B';
    

    sieht z.B. fuer die virtuelle Maschine dann so aus:

    p = 78A9:00000000
    78A9:00000000 = A
    78A9:00000001 = B
    

    Der Selektor-Lookup wuerde ueber eine Tabelle der Form:

    MemDescriptor table[0X10000];
    

    erfolgen.

    Im 80x86 / Pentium Prozessor wird das ueber spezielle Lookup-Tables gemacht, siehe Prozessorhandbuch.



  • Wenn du damit leben kannst, dass du dann dafür Unterstützung vom Kernel brauchst und maximal ca. 8000 Speicherblöcke allozieren kannst, na gut...



  • Ringding schrieb:

    Wenn du damit leben kannst, dass du dann dafür Unterstützung vom Kernel brauchst und maximal ca. 8000 Speicherblöcke allozieren kannst, na gut...

    Bei einer virtuellen Maschine lege doch ich die Funktionsweise fest. Das hat mit dem Betriebssystem ueberhaupt nix zu tun.

    Und die Groesse der Tabelle, sowie Deskriptorformat etc. kann ich ja auch selber festlegen.



  • Ok, würde in den meisten Fällen funktionieren. Man bräuchte aber dann auch einen recht großen int-artigen Typ, der so einen Pointer aufnehmen kann. int_ptr_t oder so ähnlich heißt das in C99, ich hab's vergessen...



  • Ringding schrieb:

    Ok, würde in den meisten Fällen funktionieren. Man bräuchte aber dann auch einen recht großen int-artigen Typ, der so einen Pointer aufnehmen kann. int_ptr_t oder so ähnlich heißt das in C99, ich hab's vergessen...

    Sag mal ... hast Du schon mal was von "struct" gehoert?

    struct vmptr_t {
       int selector;
       int offset;
    };
    

    zum Bleistift.

    Oder gleich:

    class scopedescriptor_t {
       public:
       char* memory;
       size_t memsize;
    };
    class vmptr_t {
       public:
       scopedescriptor_t* desc;
       size_t offset;
    };
    

    Das koennte z.B. ein C++ nach C++ Transcompiler verwenden,
    um z.B.

    // char* p = new char[2]; vorausgesetzt
    p[0] = 'A';
    p[1] = 'B';
    

    zu uebersetzen in:

    // vmptr_t p = vm_create_char_vector( 2 ); etc.
    if ( p.offset + 0U < p.desc->memsize ) p.desc->memory[0U] = 'A'; else throw vm_exception_pointer_violation( p, 0U );
    if ( p.offset + 1U < p.desc->memsize ) p.desc->memory[1U] = 'B'; else throw vm_exception_pointer_violation( p, 1U );
    

    Jetzt alle Klarheiten beseitigt? 😉


Anmelden zum Antworten