unskilled schrieb:
clear() muss schon arr und len auf Null setzen, sonst zerstört es ja die Invarianten.
was sind invarianten? ich konnt auch bei google via invariants nichts auf die schnelle finden.
Invarianten sind Bedingungen, die immer erfüllt sein müssen:
http://de.wikipedia.org/wiki/Invariante_(Informatik)
Wenn diese Invarianten den Zustand eines Objekts "einschränken", nennt man sie "class invariant":
http://en.wikipedia.org/wiki/Class_invariant
In dem Beispiel hier, kann man davon ausgehen, dass eine solche Invariante len == 0 || arr != 0 ist.
Weitere die sich in C++ allerdings nicht so ohne weiteres prüfen lassen wären: arr == 0 || is_valid_array_pointer(arr) oder len == 0 || allocated_size(arr) >= len .
Das steht zwar in diesem Beispiel nirgends, aber es ist vernünftig es anzunehmen. Bzw. man kann es auch mehr-oder-weniger aus dem Code der Klasse rauslesen.
Kurz: die Klasseninvarianten definieren was "gültiger Zustand" für Objekte der Klasse bedeutet.
des weiteren sollte es ja reichen, length auf 0 zu setzen
auf anhieb ist mir jetzt auch kein szenario eingefallen, wo es irgendetwas kaputt macht.
Nö, reicht nicht.
Würde reichen, wenn man Clear() so implementieren würde
void Clear()
{
if (len)
{
delete [] arr;
arr = 0; // jetzt optional
len = 0;
}
}
Sonst würde bei mehrmaligem Aufruf von Clear() ja das bereits gelöschte Array nochmal gelöscht.
Und den Assignment-Operator müsste man so anpassen, dass er erstmal guckt ob "other.len" auch nicht 0 ist, und wenn doch auch das arr = new type[other.len] überspringen. Sonst würde dort ein "zero size array" erzeugt, das nie mehr freigegeben wird. Weil wir ja Clear() dahingehend modifizieren mussten, dass Clear() das nicht mehr machen würde, soband len == 0 .
MMn. ist es da viel einfacher, die Invariante arr == 0 || is_valid_array_pointer(arr) zu wählen. Also in Worten: wenn "arr" nicht Null ist, muss es auch auf was gültiges zeigen.
tippfehler
assert(index >= len); ist natürlich falsch, sry war aber eher nen flüchtigkeitsfehler als nur ein tippfehler: assert(index < len);
Ich meinte das ref.l im Copy-Ctor. Die Klasse hat kein Member namens "l". Das war natürlich auch ein Flüchtigkeitsfehler und kein Tippfehler.
ps: um das re-throw im Ctor loszuwerden (...)
hab ich auch noch nie was von gehört; klingt aber höchst interessant. hast du nen link dazu? wäre toll
Link finde ich auf die Schnelle keinen.
Worum es geht hab' ich aber eh schon beschrieben.
Die Sache mit dem Debugger sollte klar sein.
Und die andere Sache, also dass es günstig sein kann wenn kein Stack-Unwinding passiert bevor terminate() aufgerufen wird...
Zwei Dinge: erstmal kann man ja nen eigenen Handler für terminate() definieren. Da drinnen kann man z.B. nen Crashdump schreiben, und nach Hause mailen/FTPen/POSTen. Der Vorteil von "kein Unwinding" ist dann der selbe wie beim "live" Debuggen: man sieht im Debugger, wenn man den Crashdump aufmacht, den Zustand des Programms zu dem Zeitpunkt wo der "ursprüngliche" Fehler passiert ist, und nicht einem, wo schon Stackunwinding zur "rethrow" Stelle gemacht wurde.
Der zweite Grund ist etwas umstritten...
Wenn ein Programm eine Exception wirft, die niemand fängt, dann bedeutet das normalerweise einen Programmierfehler. Das Programm hat also etwas gemacht, womit der Programmierer nicht gerechnet hat. Und es soll abgebrochen werden.
Jetzt ist die Frage: soll man in dem Zustand noch weiteren Code ausführen, der sich darauf verlässt dass sämtliche Invarianten noch gültig sind? (Also dass alle Objekte bzw. das gesamte Programm sich noch in einem gültigen Zustand befinden.)
Und das halte ich für eine halbwegs fragwürdige Sache, zumal ja bereits etwas passiert ist, mit dem keiner gerechnet hat. Das Programm befindet sich also garantiert in einem irgendwie "ungültigen" Zustand, sonst hätte es nie einen Punkt erreicht, an dem eine Exception geworfen wird, die keiner fängt.
Sich dann darauf zu verlassen dass das Stack-Unwinding bis zu einem bestimmten Punkt noch klappt, und dabei kein Unsinn produziert wird, ist ein halbwegs gewagtes Pokerspiel.