new und realloc



  • @camper:
    entwickelst du selber compiler oder woher kommt dein extrem gutes fachwissen?
    :xmas2:



  • ok, damit dürfte alles geklärt sein^^

    Aber hab noch eine Frage zu dem Code:

    new( q + i ) T( p[ i ] );
    

    Gibt man da mit q+i die Speicherstelle an, wo das Objekt erstellt werden soll?



  • 😕
    was ist POD
    was ist alignment
    gehts auch noch komplizierter? :p
    gehts auch so?

    template <class t>
    inline void carray<t>::set_size(int size)
    {
      if (size == _size)
        return;
      try
      {
        _data = (t**) realloc (_data, size * sizeof(t*));
        if (size && !_data)
          throw memory_exception(0);
        _upper_bound = min(size - 1, _upper_bound);
        for(int i = _size; i < size; i++)
          _data[i] = 0;
        _size = size;
      }
      catch(cexception e)
      {
        _size = 0;
        _upper_bound = -1;
        cout << e;
      };
    };
    

    cexception, memory_exception: fehlerklassen von mir
    _data: array mit den zeigern
    _size: größe des allozierten array
    _upper_bound: größter zulässiger index (kann auch kleiner als _size-1 sein)

    wenn das so nicht geht, wüsste ich gern wo genau die probleme liegen bzw welchen einschränkungen diese version unterliegt, da sie bis jetzt funktioniert.



  • POD - keine Ahnung^^

    Alignment - IMO wird der Speicher den du dir holst, auf eine gerade Bytezahl gestellt. D.h. wenn du dir 1 Byte holst (malloc/realloc/new), ist der Speicher dafür je nach System 4, 8, 16 Bytes groß oder so.

    Das Problem bei deinem Code ist, dass, wenn der Speicher verkleinert wird, der Destruktor für die entfallenen Objekte nicht aufgerufen wird. Für mehr Objekte wird der Konstruktor für die neuen nicht aufgerufen. Und wenn die Objekte "verschoben" werden, weil realloc Speicher an einer anderen Stelle zurückgibt, kriegen die Objekte nix davon mit, dass sie woanders liegen, was zu Problemen führen kann.

    Bei campers (abgefahrenem) Code werden size-Anzahl Objekte neu erzeugt, für die wird der Copy-Konstruktor mit Referenz auf das alte Objekt aufgerufen. Die alten werden dann dekonstrukturiert.


  • Mod

    FreakyBKAs code enthält zusätzlich ein Speicherleck in:

    _data = (t**) realloc (_data, size * sizeof(t*));
    

    wenn die Anforderung nicht erfüllt werden kann (realloc liefert 0 zurück). Denn der ursprüngliche Speicherblock wird dann (richtigerweise) nicht freigegeben. Der Destruktoraufruf ist kein Problem, denn es geht ja hier nur um Pointer.



  • das problem ist also, wenn realloc 0 zurückgibt hab ich keine zeiger mehr auf die objekte?


  • Mod

    FreakyBKA schrieb:

    das problem ist also, wenn realloc 0 zurückgibt hab ich keine zeiger mehr auf die objekte?

    exakt.


  • Mod

    FreakyBKA schrieb:

    das problem ist also, wenn realloc 0 zurückgibt hab ich keine zeiger mehr auf die objekte?

    exakt. Die Funktion sollte am besten nichts verändern, wenn sie nicht in der Lage ist, ihre Funktion auszuführen. Du veränderst aber den member _data bevor du weißt, ob nicht eine exception geworfen werden muss.



  • also wäre folgendes besser:

    template <class t>
    inline void carray<t>::set_size(int size)
    {
      if (size == _size)
        return;
      try
      {
        t** tmp = (t**) realloc (_data, size * sizeof(t*));
    
        if (size && !tmp)
          throw memory_exception(0);
    
        _data = tmp;
        for(int i = size; i < _size; i++)
        {
          delete _data[i];
          _data[i] = 0;
        };
        for(int i = _size; i < size; i++)
          _data[i] = 0;
        _upper_bound = min(size - 1, _upper_bound);
        _size = size;
      }
      catch(cexception e)
      {
        cout << e;
      };
    };
    

  • Mod

    FreakyBKA schrieb:

    also wäre folgendes besser:

    template <class t>
    inline void carray<t>::set_size(int size)
    {
      if (size == _size)
        return;
      try
      {
        t** tmp = (t**) realloc (_data, size * sizeof(t*));
    
        if (size && !tmp)
          throw memory_exception(0);
    
        _data = tmp;
        for(int i = size; i < _size; i++)
        {
          delete _data[i];
          _data[i] = 0;
        };
        for(int i = _size; i < size; i++)
          _data[i] = 0;
        _upper_bound = min(size - 1, _upper_bound);
        _size = size;
      }
      catch(cexception e)
      {
        cout << e;
      };
    };
    

    schon. wie kommst du eigentlich auf die Idee, per delete _data[i] daten zu löschen, wenn du schon realloc aufgerufen hast und _data[i] außerhalb deines Datenblocks liegt ? 🙂 Das mußt du vorher machen. Glücklicherweise schlägt realloc niemals fehl, wenn die angeforderte Größe nicht größer als der bereitsvorliegende Datenblock ist - du hast hier also kein Problem.



  • stimmt, hab ich übersehen werde ich gleich mal ändern.



  • was mache ich denn wenn ich einen typ der form

    int[2], char*
    

    oder so habe, also quasi wieder dynamischer speicher.
    der muss ja auch wieder ordnungsgemäß freigegeben werden.



  • Nein. Du musst nur Speicher wieder freigeben, den du mit new oder malloc angefordert hast.


Anmelden zum Antworten