Verbesserung an Template Klasse gegen Array Überlauf



  • otze schrieb:

    template <class typ,int size> typ MyArray<typ,size>::operator=(const MyArray& a )
    {
        if(this!=&a){
            MyArray temp(a);
            std::swap(array,temp.array);
            std::swap(aktSize,temp.aktsize);
        }              
    }
    

    Wieso muss ich hier ne extra Kopie von "a" namens "temp" erstellen und kann nicht direkt swap anwenden ???



  • weil a keine kopie sondern eine referenz auf das als parameter übergebene objekt ist, darf nicht einfach swap benutzt werden, weil sonst keine wertekopie sondern ein einfacher werteaustausch stattfinden würde.

    dh wenn du a=b machen würdest, würde ohne die kopie a den wert von b haben, b aber den alten wert von a!



  • Achja stimmt ja, danke...
    Habe nur "einseitig" gedacht 😃



  • So jetzt endlich(hoffentlich) der komplette/perfekte 😉 Quelltext:
    Vielleicht braucht ihn ja mal irgendjemand :p 😛

    template<class typ,int size> class MyArray {
    
                   typ* array;
                   int aktSize;
                   void grow(int newSize);
        public:
                   MyArray();
                   MyArray(const MyArray &Array_kopie);
                   MyArray(typ* arr);
    
                   typ operator=(const MyArray& a);
                   typ &operator[] (unsigned int i);
                   const typ &operator[](unsigned int i) const;
    
                    ~MyArray() { delete [] array; }
    
    };
    
    template<class typ,int size> MyArray<typ,size>::MyArray()
    {
                   aktSize=size;
                   array=new typ[size];
    }
    
    template<class typ,int size> MyArray<typ,size>::MyArray(const MyArray &Array_kopie)
    {
                  array=new typ[Array_kopie.aktSize];
                  aktSize=Array_kopie.aktSize;
                  for(int i=0;i<Array_kopie.aktSize;i++)
                           array[i]=Array_kopie.array[i];                
    }
    
    template<class typ,int size> MyArray<typ,size>::MyArray(typ* arr)
    {
                   aktSize=size;
                   array=new typ[size];
    
                   for(int i=0;i<size;i++)
                   array[i]=arr[i];
    
    }
    
    template <class typ,int size> typ &MyArray<typ,size>::operator[](const unsigned int i)  
    {
             if(i>aktSize) grow(i);
             return array[i];
    }
    
    template <class typ,int size> const typ &MyArray<typ,size>::operator[](unsigned int i) const  
    {
                  if(i<aktSize) 
                                return array[i];
                  else
                                throw out_of_range("Out of Range !!!");   
    
    }
    
    template <class typ,int size> typ MyArray<typ,size>::operator=(const MyArray& a )
    {
             if(aktSize<a.aktSize) 
             { 
               delete [] array;
               array=new typ[a.aktSize];
             }
    
             MyArray temp(a);
             std::swap(array,temp.array);
             std::swap(aktSize,temp.aktSize); 
    
             return *this;     // Ist nicht zwigend erforderlich oda ?            
    }
    
    template <class typ,int size> void MyArray<typ,size>::grow(int newSize)
    {
             typ* temparray;
             int altSize=aktSize;
    
             aktSize=newSize * 2;
    
             temparray=new typ [aktSize];
    
             for(int i=0;i<altSize;i++)
                     temparray[i]=array[i];
    
             delete [] array;
             array=temparray;
    
    }
    


  • template<class typ,int size> class MyArray {
    

    warum ist size ein template-argument? kannst doch beruhigt die initial size auf 64 festegen oder als konstruktorargument nehmen. vorteil: nicht jedes array braucht eigenen code und die exe wird kleiner, das programm am ende scneller.

    MyArray(); 
                   MyArray(const MyArray &Array_kopie); 
                   MyArray(typ* arr); 
    
                   typ operator=(const MyArray& a); 
                   typ &operator[] (unsigned int i); 
                   const typ &operator[](unsigned int i) const; 
    
                    ~MyArray() { delete [] array; }
    

    besser, man macht konstruktoren, zuweisungsop und dtor zusammen.

    MyArray(); 
                   MyArray(typ* arr); 
                   MyArray(const MyArray &Array_kopie); 
                   typ operator=(const MyArray& a); 
                    ~MyArray() { delete [] array; } 
    
                   typ &operator[] (unsigned int i); 
                   const typ &operator[](unsigned int i) const;
    

    und der rückgabetyp des op= ist gelinde gesagt gewagt.

    template<class typ,int size> MyArray<typ,size>::MyArray() 
    { 
                   aktSize=size; 
                   array=new typ[size]; 
    }
    

    leider muss das umgeschrieben werden zu

    template<class typ,int size> MyArray<typ,size>::MyArray() 
    :array(new typ[size])//das hier wichtig für wenn exceptions
    ,aktSize(size)
    { 
    }
    
    template<class typ,int size> MyArray<typ,size>::MyArray(typ* arr) 
    { 
                   aktSize=size; 
                   array=new typ[size]; 
    
                   for(int i=0;i<size;i++) 
                   array[i]=arr[i]; 
    
    }
    

    naja, wollen wir nicht doch lieber begin und end übergeben? so isses ein wenig komisch.

    template <class typ,int size> const typ &MyArray<typ,size>::operator[](unsigned int i) const   
    { 
                  if(i<aktSize) 
                                return array[i]; 
                  else 
                                throw out_of_range("Out of Range !!!");   
    
    }
    

    was soll das denn? das widerstebt mir. irgendwas ist da ganz komisch.

    return *this;     // Ist nicht zwigend erforderlich oda ?
    

    doch. für

    a=b=c;
    
    typ* temparray; //keine variablen leer stehen lassen
    

    und mach dazu noch ein StaticArray, das nicht wachsen kann und nicht new benutzt.



  • volkard schrieb:

    template<class typ,int size> class MyArray {
    

    warum ist size ein template-argument? kannst doch beruhigt die initial size auf 64 festegen oder als konstruktorargument nehmen. vorteil: nicht jedes array braucht eigenen code und die exe wird kleiner, das programm am ende scneller.

    Stimmt. Hast vollkommen recht 😃
    Das dann für jedes Array nen eigener Code erzeugt wird, daran hab ich nicht gedacht... 😃

    volkard schrieb:

    MyArray(); 
                   MyArray(const MyArray &Array_kopie); 
                   MyArray(typ* arr); 
                  
                   typ operator=(const MyArray& a); 
                   typ &operator[] (unsigned int i); 
                   const typ &operator[](unsigned int i) const; 
                                  
                    ~MyArray() { delete [] array; }
    

    besser, man macht konstruktoren, zuweisungsop und dtor zusammen.

    Sind doch !!?? 😕 😕 Oder meinste alle auf einen Haufen.

    volkard schrieb:

    MyArray(); 
                   MyArray(typ* arr); 
                   MyArray(const MyArray &Array_kopie); 
                   typ operator=(const MyArray& a); 
                    ~MyArray() { delete [] array; } 
    
                   typ &operator[] (unsigned int i); 
                   const typ &operator[](unsigned int i) const;
    

    und der rückgabetyp des op= ist gelinde gesagt gewagt.

    O man. Upps soll natürlich MyArray heißen...

    volkard schrieb:

    leider muss das umgeschrieben werden zu

    template<class typ,int size> MyArray<typ,size>::MyArray() 
    :array(new typ[size])//das hier wichtig für wenn exceptions
    ,aktSize(size)
    { 
    }
    

    Von dem Code verstehe ich nur Bahnhooof 😕

    volkard schrieb:

    naja, wollen wir nicht doch lieber begin und end übergeben? so isses ein wenig komisch.

    Ok OK 🕶

    volkard schrieb:

    template <class typ,int size> const typ &MyArray<typ,size>::operator[](unsigned int i) const   
    { 
                  if(i<aktSize) 
                                return array[i]; 
                  else 
                                throw out_of_range("Out of Range !!!");   
            
    }
    

    was soll das denn? das widerstebt mir. irgendwas ist da ganz komisch.

    Habe ich nen Reh umgefahren ??? Was ist daran komisch 😕

    volkard schrieb:

    typ* temparray; //keine variablen leer stehen lassen
    

    Wie wo was ???? Was ist den daran Leer 😕

    volkard schrieb:

    und mach dazu noch ein StaticArray, das nicht wachsen kann und nicht new benutzt.

    Meinst du noch ne Template-Klasse mit normalen Arrays ?



  • genau, ne template klasse mit normalen arrays. dann hat wenigsten der template parameter "size" einen sinn 😃



  • Was bringt mir dann diese Klasse. Was soll ich denn da bei einem Arrayüberlauf machen? --> Nichts einfach so lassen oder ???



  • Freak_Coder schrieb:

    Was bringt mir dann diese Klasse. Was soll ich denn da bei einem Arrayüberlauf machen? --> Nichts einfach so lassen oder ???

    assert //ziemlich gut
    oder
    __asm int 3 //lustig, doch hilfreich
    oder
    throw //pass nicht zum c++-stil

    oder ganz perfekt ein eigenes ASSERT, was erst asm int 3 macht (aber nur wenn ein debugger mitläuft) und dann throw (ne eigene exception-klasse mit __LINE__ und __FILE__ übergeben).

    ach, mach erstmal einfach assert. indexgrenzenüberschreitungen sind halt so häufige fehler und mit ner eigenen array-klasse so einfach wegzumachen, daß man eigenlich immer ne eigene klasse nehmen sollte.



  • Ok! Weiß zwar noch nicht über asserts aber kann mir ja das Wissen aneignen 😃

    Wäre mal gut wenn du mal auf Seite 4 schauen würdest da habe ich dir noch ne Menge fragen gestellt(letzer Beitrag(Die assert frage hat sich dann wohl da geklärt))...



  • Freak_Coder schrieb:

    Wäre mal gut wenn du mal auf Seite 4 schauen würdest da habe ich dir noch ne Menge fragen gestellt(letzer Beitrag...

    dachte, alles sei geklärt.

    mit leer meinte ich uninitialisiert. siehe http://www.volkard.de/Cpp/Tutorial/Grundlagen/Variablen/index.html

    und ja, ich meine eine array-klasse um ein normales array. der wunsch müßte auf seite 1 schon stehen.

    template<class typ,int size> class MyArray {
    	typ array[size];
        public: 
    	typ &operator[] (unsigned int i); 
        const typ &operator[](unsigned int i) const; 
    };
    

    und in die op[] fein assert oder irgendwas rein.



  • Wenn ich das richtig gesehen habe gibt der op= immer noch ne Kopie zurück und ist damit noch etwa doppel so langsam wie er sein müßte.



  • Habe jetzt meine Klasse wieder umgeändert, nur gibt es etwas was ich noch nicht verstehe:

    template<class typ,int size> MyArray<typ,size>::MyArray() 
    :array(new typ[size])// Mit dieser schreibweise ruft man doch ander Ctors auf oda
    ,aktSize(size)        // aber was hat array() und aktSize() da zu suchen (nichts kapisch)
    { 
    }
    

    Einer ne Erklärung vielleicht oder nen Link ???



  • Freak_Coder schrieb:

    Einer ne Erklärung vielleicht oder nen Link ???

    weder noch. ich hab da gelogen. deine version ist hübscher.



  • 😕 😕 Häää, wenn das so ist !
    Aber gibt es diese Schreibweise wirklich oder auch gelögen oda ??? 😕

    Und was war damit:

    volkard schrieb:

    template <class typ,int size> const typ &MyArray<typ,size>::operator[](unsigned int i) const   
    { 
                  if(i<aktSize) 
                                return array[i]; 
                  else 
                                throw out_of_range("Out of Range !!!");   
            
    }
    

    was soll das denn? das widerstebt mir. irgendwas ist da ganz komisch.

    Ist da auch was gelogen oder? Caipi meinte ich solls so machen ?



  • Freak_Coder schrieb:

    😕 😕 Häää, wenn das so ist !
    Aber gibt es diese Schreibweise wirklich oder auch gelögen oda ??? 😕

    die gibt es. und irgendwann wird sie besser als die jetzige. im moment ist die jetzige besser weil übersichtlicher.

    Und was war damit:

    volkard schrieb:

    was soll das denn? das widerstebt mir. irgendwas ist da ganz komisch.

    Ist da auch was gelogen oder? Caipi meinte ich solls so machen ?

    das widerstebt mir wirklich. irgendwas ist da wirklich ganz komisch.

    das klint so, als wolle man programmierfehler zur laufzeit fangen und heilen.



  • Weil ich irgendwie nicht verstehe was du meinst werde ich es einfach mal rausnemen und nur ein return (vorerst) reinsetzten.



  • Hier nun nochmal alles:

    template<class typ> class MyArray {
    
                   typ* array;
                   int aktSize;
                   void grow(size_t newSize);
        public:
                   MyArray(size_t size);
                   MyArray(const MyArray &Array_kopie);
                   MyArray(size_t size,typ* arr_anfang,typ* arr_ende);
    
                   MyArray &operator=(const MyArray& a);
                   typ &operator[] (unsigned int i);
                   const typ &operator[](unsigned int i) const;
    
                    ~MyArray() { delete [] array; }
    
    };
    
    template<class typ> MyArray<typ>::MyArray(size_t size)
    {
                   aktSize=size;
                   array=new typ[size];
    }
    
    template<class typ> MyArray<typ>::MyArray(const MyArray &Array_kopie)
    {
                  array=new typ[Array_kopie.aktSize];
                  aktSize=Array_kopie.aktSize;
                  for(int i=0;i<Array_kopie.aktSize;i++)
                           array[i]=Array_kopie.array[i];
    }
    
    template<class typ> MyArray<typ>::MyArray(size_t size,typ* arr_anfang, typ* arr_ende)
    {
                   aktSize=size;
                   array=new typ[size];
    
                   for(int i=0;&(arr_anfang[i])!=arr_ende;i++)
                   array[i]=arr_anfang[i];
    
    }
    
    template <class typ> typ &MyArray<typ>::operator[](unsigned int i)
    {
             if(i>aktSize) grow(i);
             return array[i];
    }
    
    template <class typ> const typ &MyArray<typ>::operator[](unsigned int i) const
    {
                  return array[i];
    }
    
    template <class typ> MyArray<typ> &MyArray<typ>::operator=(const MyArray& a )
    {
             if(aktSize<a.aktSize)
             {
               delete [] array;
               array=new typ[a.aktSize];
             }
    
             MyArray temp(a);
             std::swap(array,temp.array);
             std::swap(aktSize,temp.aktSize);
    
             return *this;     
    }
    
    template <class typ> void MyArray<typ>::grow(size_t newSize)
    {
             int altSize=aktSize;
    
             aktSize=newSize * 2;
    
             typ* temparray=new typ [aktSize];
    
             for(int i=0;i<altSize;i++)
                     temparray[i]=array[i];
    
             delete [] array;
             array=temparray;
    
    }
    
    //----------------------------------------------------------------------------
    
    template <class typ,size_t size> class StaticArray {
    
                    typ array[size];
            public:
                    StaticArray() { }
                    StaticArray(typ* arr_anfang,typ* arr_ende);
    
                    typ &operator[] (unsigned int i);
                    const typ &operator[](unsigned int i) const;
    
    };
    
    template<class typ,size_t size> StaticArray<typ,size>::StaticArray(typ* arr_anfang, typ* arr_ende)
    {
                   for(int i=0;&(arr_anfang[i])!=arr_ende;i++)
                   array[i]=arr_anfang[i];
    
    }
    
    template <class typ,size_t size> typ &StaticArray<typ,size>::operator[](unsigned int i)
    {
                  assert(i<size);
                  return array[i];
    }
    
    template <class typ,size_t size> const typ &StaticArray<typ,size>::operator[](unsigned int i) const
    {
                  assert(i<size);
                  return array[i];
    }
    

    In was für einen Datei speichert man am besten nun so was ab um nachher damit in eigenen Programmen arbeiten zu können.

    Und sonst alles diesmal in ORDNUNG ....



  • das ganze kommt am besten in einen eigenen header, also eine *.hpp 🙂


Anmelden zum Antworten