Verbesserung an Template Klasse gegen Array Überlauf
-
Freak_Coder schrieb:
template <class typ,int size> const typ &MyArray<typ,size>::operator[](unsigned int i) const
{
return array[i]; /* Was soll ich hier machen wenn nen indexüberschreitung auftritt,
einfach dann den UNSINNIGEN Wert ausgeben lassen, oder??? */}
Bei ungültigem Index würde ich eine Exception vom Typ out_of_range werfen.
Caipi
-
Der op= ist noch ein bißchen teuer im Moment. Das Argument wird by value übergeben, das heißt Du ziehst erst ne Kopie um die danach zu kopieren... und gibst dann nochmal ne Kopie zurück. Da sollte auf jeden Fall ne Referenz hin.
Lösung: entweder auf Copy & swap umsteigen oder by reference übergeben, dann aber auf Selbszuweisung achten.
-
Lösung: entweder auf Copy & swap umsteigen oder by reference übergeben, dann aber auf Selbszuweisung achten.
oder erst auf selbst zuweisung achten und dann copy and swap
das sähe dann so aus:
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); } }
-
otze schrieb:
oder erst auf selbst zuweisung achten und dann copy and swap
gleich copy&swap ist besser. weil selbstzuweisungen echt so selten sind, daß man sich aus performance-sicht den test sparen sollte. und notwendig isser ja nicht bei copy&swap.
-
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 :ptemplate<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++-stiloder 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.