Zugriffverletzung beim automatischen Vergrößern eines dynamischen Arrays



  • Hallo zusammen,
    mich plagt zur Zeit ein Fehler und ich finde einfach keine Lösung. Zwar habe ich darüber schon indirekt im "C++" Forum darüber gesprochen, doch da ich alles mit dem Builder mache, finde ich es angemessener, dass ich hier meine Frage stelle. Ich habe ein Template, dass ein dynamisches Array erstellt. Das Besondere daran ist, dass sich dieses Array automatisch vergrößert, wenn ich beispielsweise auf ein nicht vorhandenes Element zugreifen will oder plötzlich mehr in das Array rein soll, als vorgesehen. Dazu habe ich ein Template geschrieben:

    template <typename T> class DynArray
    {
     public:
      DynArray() { //Default-Konstruktor
       str.len=1;
       str.array=new T[1];
       str.array[0]=0;
      }
      DynArray(int size) { //Überladener Konstruktor
       str.len=size;
       str.array=new T[size];
       for (int i=0; i<size; i++)
        str.array[i]=0;
      }
      ~DynArray() {
       delete [] str.array;
      }
      int Length (void) {
       return str.len;
      }
      int LengthWritten (void) //Diese Methode gibt die Zahl aller beschriebender ELemente aus
      {
       int number=0;
       for (int i=0; i<str.len; i++)
       {
        if (str.array[i]!=0) number+=1;
       }
       return number;
      }
      void NewSize (int NewSize) {  //Die wichtigste Methode. Sie vergrößert das Array
        T *temp=new T[str.len];
        for (int i=0; i<str.len; i++)
         temp[i]=str.array[i];
        delete [] str.array;
        str.array = new T[NewSize];
        for (int i=0; i<NewSize; i++) {
         if(i<=str.len) str.array[i]=temp[i];
         else str.array[i]=0;
        }
        str.len=NewSize;
        delete [] temp;
       }
      void Insert (int key, T value) {  //Hinzufügen eines Elements
       if (key > str.len || str.len==0) NewSize(key+1);
       str.array[key]=value;
      }
      T Read (int index) { //Auslesen eines Elements
       if (index>str.len) NewSize(index+1);
      return str.array[index];
      }
      void Delete (int index) {
       if (index>str.len) NewSize(index+1);
       delete str.array[index];
       str.len--;
      }
      T operator [] (int index) { //Ebenfalls das Auslesen eines Elements
       if(index >= str.len) NewSize(index);
       return str.array[index];
      }
     private:
      struct Ar {
       T *array;
       int len;
       } str;
    };
    

    Leider funktionert das nicht so, wie ich es haben möchte. Dazu habe ich folgendes einfaches Programm:

    DynArray <int> Instanz(3);
     Instanz.Insert(0,1); //ok
     Instanz.Insert(1,2); //ok
     Instanz.Insert(2,3); //ok
     Instanz.Insert(3,4); //Fehler
    
     int zahl=Instanz.Length();
     for (int i=0; i<zahl; i++)
     {
      ShowMessage(Instanz[i]);
     }
    

    Hier gibt es mehrere Probleme.

    1.) Ich kann den Default-Konstruktor nicht verwenden. Wenn ich das schreibe

    DynArray <int> Instanz();
    

    dann kommt eine Fehlermeldung, wenn ich den Punktoperator schreibe (Auf linker Seite der Struktur ist . oder .* erforderlich) und die Vorschlagsliste aller Methoden öffnet sich auch nicht.

    2.) Wenn ich nun den überladenen Konstruktor verwende, dann funktioniert das Vergrößern des Arrays nicht. Es kommt ein Fenster, in dem eine Zugriffs-verletzung steht. Wenn ich weitermache, dann öffnet sich das CPU-Fenster (wobei ich damit nichts anfangen kann). All diese Meldungen kenne ich, wenn ich beispielsweise auf ein nicht vorhandenes Arrayelemt zugreifen möchte, doch sollte dann das Template greifen. Durch ein paar Tests habe ich herausgefunden, dass zwar die Methode "NewSize" aufgerufen wird (da ich durch das letzte Insert das Array vergrößere), doch das eigentliche Vergrößern schlägt fehlt.

    Außerdem kommen öfter Compilerfehler wie:

    [C++ Fataler Fehler] Unit1.h(12): F1004 Interner Compiler-Fehler at 0xc4b855 with base 0xc10000

    Könnt ihr mir helfen, den oder die Fehler zu finden, denn ich bin am Verzweifeln....

    Vielen, vielen Dank
    lg, freakC++



  • Hallo,
    da bin ich schon wieder. Nachdem ich meinen Computer nun 3 mal neugestartet habe, ist der Fehler weg. Vielleicht lag es alles wirklich an einem internen Compilerfehler....komisch.

    Nur ein Problem bleibt: Ich kann immernoch nicht den Standartkonstruktor aufrufen.

    Sobald ich einfach nur zwei leere Klammern schreibe, dann funktionieren die Methoden nicht mehr (siehe Post davor). Woran kann das liegen?

    Vielen Dank für eure Hilfe
    lg, frekC++



  • Hallo

    1. Diese Zeile

    DynArray <int> Instanz();
    

    bringt den Compiler durcheinander, denn er glaubt das wäre die Deklaration einer Funktion. Um eine Instanz der Klasse zu
    dekalarieren, must du die Klammern weglassen :

    DynArray <int> Instanz;
    

    2. Du kommst irgendwo mit deiner Speicherarbeit durcheinander. Hab jetzt keine Zeit da genau durchzuschauen. Aber ich frag mich eh warum du so etwas neu schreibst, wo es doch wenigstens DynamicArray schon gibt. Wenn es dir nur um das automatische Vergrößern geht, dann schreib dir eben eine einfache Insert-Methode :

    template <typename Type>
    void DynInsert(DynamicArray<Type>& array, int pos, const Type& value)
    {
      if (array.Length <= pos)
        array.Length = pos +1;
      array[pos] = value;
    }
    ...
     DynamicArray<int> Instanz;
     DynInsert(Instanz, 10, 2);
     ShowMessage("Length : " + IntToStr(Instanz.Length) + ", Item : " + IntToStr(Instanz[10]));
    

    Damit sparst du dir viel Ärger.

    3. Du hast deine Klasse zwar als Template angelegt, aber trotzdem unnötigerweise die verwendbaren Typen einfgeschränkt.

    str.array[0]=0;
    

    Diese Anweisung wird nur bei Typen funktionieren, die expliziet oder impliziert durch einen Integer erstellt werden können. Um das weiter zu verallgemeinern, must du schreiben :

    str.array[0]=T();
    

    Damit funktionkiert die Anweisung mit allen Typen die einen Standardkonstruktor anbieten (und diese Einschränkung hast du ja sowieso durch die new-Aufrufe).

    bis bald
    akari


Anmelden zum Antworten