vlib
-
Ben04 schrieb:
Ich hab schon viele Artikel im Internet die zu folgendem geraten haben gesehen:
class Foo{ public: ~Foo(){ try{ bar(); }catch(...){ } } };
lol. das ist auch sachlich falsch, weil ich dann bei ner nicht-fertig-geschriebenen datei denke, sie sei fertig. dann schon lieber fürstlich abschmieren. ich stelle mir nur mal vor, mein textverarbeitungsprogramm würde mit solchen methoden schreiben.
Das wäre ja schon beinahe tötlich für dein ASSERT. Da ein fehlerhaftes Program ja gar nicht mal abstürtzt.
zur vlib muß dann auch ein style-guide her. jo, ich schreib ihn gerade mal.
Vielleicht wäre folgender Ansatz eine Lösung:
[cpp]
// Nicht von Error ableiten, soll ja nicht
// gefangen werden oder?
[/quote]
stimmt. soll in der main gefangen werden, da mach ich halt die zeile dazu.den zähler überleg ich mir noch, ob mir irgendein fall einfällt, wo der stört.
-
destruktoren dürfen nix tun, was normale laufzeitfehler verursachen könnte. man wird nicht mit assert fragen, ob daten auf die platte geschrieben werden konnten. man wird beim schreiben trotzdem immer testen (bei mir mit SYSCHECK) und gegebenenfalls exceptions werfen.
ich kann nur verhindern, daß bei destruktoren unfug passiert, wenn ich dort nichts aufrufe, was laufzeitfehler haben könnte. insofern ist flush() im destruktor von FileReader schlecht.
andererseits muß aber genau dieses flush aufgerufen werden.eigentlich muss nur die erste exception geworfen werden und bei allen folgenden wird nicht geworfen, sondern auggegeben. also in raiseAssertError das if, das den zähler prüft.
-
volkard schrieb:
Ben04 schrieb:
Ich hab schon viele Artikel im Internet die zu folgendem geraten haben gesehen:
class Foo{ public: ~Foo(){ try{ bar(); }catch(...){ } } };
lol. das ist auch sachlich falsch, weil ich dann bei ner nicht-fertig-geschriebenen datei denke, sie sei fertig. dann schon lieber fürstlich abschmieren.
So "lol" ist die Idee gar nicht mal. Es steckt der gleiche Grundgedanke dahintert als hinter einer exceptionwerfenden Assertion : retten was noch zu retten ist. Eine Exception in einem Destruktor ist ein Programfehler genauso wie eine fehlgeschlagene Assertion. Ich will jetzt nicht sagen, dass dies eine Glanzlösung ist da sie sehr viele Schwächen hat. Besser wäre natürlich die fliegende Ausnahme zu fangen und durch eine AssertError Ausnahme zu ersetzen, geht aber nicht.
Zu deinem Problem mit dem flush : Flush kann eine Ausnahme werfen. Also was sind die mögliche Lösungen:
a) Flush raus aus dem Destruktor und explicit aufrufen. Schlecht da dann im Fall einer Ausnahme nie geflusht wird.
b) Flush wirft nicht und gibt einen Fehlerwert zurück den man ignoriert da man im Fehlerfall nichts schlaues machen kann.
c) try Block um flush bauen wie oben gezeigt, was eigentlich das gleiche wie b) ist.
d) Streams nicht puffern.
Ideal was die Fehlerbehandlung ist nur d. Eine Kombination aus a und d könnte ich mir auch noch vorstellen : Nicht werfende Ausgaben gruppieren und in einen eignen Scope packen und noch einen ScopeGuard hinein der das Buffern einschaltet. Durch den ScopeGuard gewinnt man zwar keine Zeile im Vergleich mit a) aber wenn man ihn vergisst ist das kein Drama. Dagegen würden bei a) die Daten verloren gehen.
-
So "lol" ist die Idee gar nicht mal.
Es ist fast immer lol, grundsätzlich alle Exception-Arten zu fangen, von ein paar sehr wenigen Fällen wie main() mal abgesehen.
retten was noch zu retten ist. Eine Exception in einem Destruktor ist ein Programfehler genauso wie eine fehlgeschlagene Assertion
Es gibt hier zwei Dinge zum differenzieren: WO tritt der Fehler auf und WAS für ein Fehler ist es. Eine Assertion ist ein Logikfehler, der gar nicht sein darf. Definitionsgemäß gibt es keinen AssertionError. In der Praxis gibt es ihn aber, weil Programmierer Menschen sind. Jetzt zum Destruktor: Er sollte nichts großartiges tun, was Exception-verdächtig ist, z.B. I/O-Sachen. Wär ja blöd, wenn beim Zerstören von etwas noch was kaputt geht. Die Hauptidee ist aber, dass der Destruktor und andere Destruktoren ihre verdammt wichtige Arbeit machen. Deshalb werde ich nicht im Destruktor eine Datenbank-Verbindung herstellen, eine Datei herausladen, dekomprimieren und auf meinen ftp hochladen. Da kann so viel schief gehen, dass mir schon schlecht wird. Aber vor einem AssertionError im Destruktor muss ich keine Angst haben, denn den gibt es definitionsgemäß gar nicht.
Auch wenn ich ein geiles Array mit Indexprüfung habe und das wirft mir ne Exception im Destruktor... warum sollte ich sie fangen? Ich darf ums Verrecken keinen ungültigen Index benutzen, Destruktor hin oder her. Bei solchen logischen Fehlern, die nicht auf Dateizugriff oder sonst was zurückzuführen sind, was nicht in meiner Macht liegt, soll das Programm sich abschießen, nichts anderes ist sinnvoll. Es gibt nichts zu retten.
Deshalb fängt man so einen Error nicht. Man fängt überhaupt niemals Exceptions, die man nicht erwartet.
-
morgen,
nach laengerer Zeit auch nochmal was von mir. Sorry das ich nichts mehr geschrieben hab, aber war in Siegen
mit der Immatrikulation und dem ganz bloeden Papierkram beschaeftigt.Hab mir die aktuelle Version mal gezogen und die geht auch prinzipiell durch den gcc4, allerdings findet
er die peekNoEof()-Funktion nicht, welche in der Reader.cpp aufgerufen wird. Kann die auch sonst nirgends
finden, hab ich doch wieder eine aeltere Version gezogen?mfg
v R
-
die Reader.hpp hat kein paakNoEof() mehr.
und die Reader.cpp ist weg. verlorengegangen. lost in space oder so. und ich hab's nicht bemerkt, daß ich keinen Reader benutzt hab.
die letzte lebende hat glaub ichReader::operator unsigned long long(){
ASSERT(!eof());
char d=peek();
if(!isDigit(d))
throw FormatError();
unsigned long long x=d-'0';
pop();
while(!eof()){
d=peek();
if(!isDigit(d)) break;
x=x*10+d-'0';
pop();
}
return x;
}angeboten, ohne peekNoEof().
hab Reader.cpp und FormatError.* wieder dazugemacht.
-
und ich konnt's nicht lassen, un hab ::swap mit metaprogrammerung und SFINAE gemacht.
alsotemplate<typename Data> typename EnableIfVoid<IsNoClass<Data>::value>::Type swap(Data& a,Data& b){ Data tmp(a); a=b; b=tmp; } template<typename Data> typename EnableIfVoid<HasSwap<Data>::value>::Type swap(Data& a,Data& b){ Data::swap(a,b); }
mit dem gcc war der code einfach so machbar. aber den auch für msvc hinzukriegen! wahninn. ne methode holt man sich mit T::swap statt &T::swap, aber das liefert trotzdem falsche ergebnisse in SFINAE. &T::swap compiliert nichtmal, beim gcc aber nur so. static methoden gehen dafür. die struct SwapBind in der meta.hpp muß global sein. innerhalb der klasse compiliert sie zwar, macht aber falsche ergebnisse. holt man sich in SFINAE mal int::swap, gibt nen INTERNAL COMPILER ERROR. einfach haarsträubend.
-
kingruedi schrieb:
Aber true und false Flags sind leider nicht so eindeutig. Mach doch ein
enum { OnHeap=true, OnStack=false };
hab die gerade in nem dreiseitigen artikel nachgewiesen. daß dein enum schlecht ist. aber das forum hat ihn geschluckt.
muss mir wohl glauben, denn den schreib ich nicht neu, würde mich nur ärgern.
-
schreib ma neu
-
Willst du die Forschungsergebnisse wirklich für dich behalten?
Vielleicht reichen ja schon Stichpunkte!
-
eih, mir fällt gerade was ganz unschönes auf.
ich wollte gerade nen Heap anfangen.
der nette trick, new(vec) Foo(x) statt vec.push_back(x) zu schreiben, der klappt gar nicht mehr bei sowas. ich muß ja nachdem der ctor aufgerufen wurde, das neue objekt noch einsortieren. wie mach ich das denn am dümmsten?
-
Meinst du, direkt an der richtigen Stelle im Heap das Objekt konstruieren? Vielleicht mit einem KeyValue-Pair. Setzt aber auch voraus, dass man vor der Konstruktion den Key feststellen kann. Vielleicht sind Zeiger doch schöner.
-
Optimizer schrieb:
Meinst du, direkt an der richtigen Stelle im Heap das Objekt konstruieren? Vielleicht mit einem KeyValue-Pair. Setzt aber auch voraus, dass man vor der Konstruktion den Key feststellen kann. Vielleicht sind Zeiger doch schöner.
lustige idee. ja, kann den key erstmal zeigen, damit er platz macht. vielleicht.
bin zur zeit am überlegen, daß ich noch nen zeiger nehme, der sagt, bis wohin der heap hepified ist und man fügt einfach hinten an und erst beim peek oder pop holt er das heapifien auf, sofern bedarf besteht.
-
In der Klasse Reader:
void pop(){ ASSERT(!eof()); ++rpos; }
Bedeutet das, dass ich eof() selber aufrufen muss, oder sollte das ein CHECK sein?
Edit: Selbst wenn das Absicht ist, peek ist so irgendwo kaputt:
char peek(){ ASSERT(!eof()); return *rpos; }
-
Mr. N schrieb:
In der Klasse Reader:
void pop(){ ASSERT(!eof()); ++rpos; }
Bedeutet das, dass ich eof() selber aufrufen muss, oder sollte das ein CHECK sein?
ich dachte an selber aufrufen. oft hat man ja konstrukte wie while(!in.eof())..., da wird das dann eh gemacht und ich wollte nicht erzeingen, daß es doppelt gemacht wird.
aber die reader-schnittstelle ist noch ganz wackelig. ich muß mal ne ordentliche factory bauen, die schnell sowas wie einen spielstand (voller polymorpher objekte) laden kann, um zu sehen, ob das so in ordnung ist.Edit: Selbst wenn das Absicht ist, peek ist so irgendwo kaputt:
char peek(){ ASSERT(!eof()); return *rpos; }
vor peek müßte auch gelten, daß !eof() gilt. bin gerade weit weg von daheim, und kann nicht an der vlib weitermachen.
ich nehme mir mal vor, die factory zu bauen, bevor ich den heap fertig mache. nee. für die factory bräuchte ich ne hashtable ider nen TST, die hab ich auch noch nicht.
also reader ist wackelkandidat.
-
geht natürlich nicht, daß ich den benutzer zwinge, zwischen zwei lesungen auf !eof() zu prüfen. er soll ja mal schreiben
Foo::Foo(Reader& in): BaseClass(in),attrib1(in),attrib2(in),attrib3(in){ }
dann moß wohl doch peek in den sauren apfel beißen und immer eof() aufrufen.
-
machste nicht mehr weiter an der vlib?
-
fan schrieb:
machste nicht mehr weiter an der vlib?
bin ein wenig blockiert durch ganz viel uminstallieren, hoffe, ich hab's bald.
und ich verlasse den gcc und schwenke um zum icc, weil ich template-placement-delete brauche.
-
g++ Nutzer können also nichts mehr mit deiner Library anfangen?
-
g++ user schrieb:
g++ Nutzer können also nichts mehr mit deiner Library anfangen?
der erste gcc-user müßte nen bug-report senden und die gcc-bauer machen den bug weg und alles ist wieder ok.