Maschienencode konvertierung
-
Paul Müller schrieb:
Hast du dein Beispiel mal getestet? Ich kann mir gut vorstellen, dass das eher ein Fall ist, wo man close() anwenden muss. Du öffnest eine Datei zum Schreiben und willst sie ein zweites Mal zum Lesen öffnen, bevor sie durch den Destruktor geschlossen wurde. Es ist immer sinnvoll, wenn man die Objektlebensdauer nicht einschätzen kann oder sie länger ist, Ressourcen nur solange zu halten, wie man sie benötigt.
Du hast RAII nicht verstanden. Solche Fälle sollte man gar nicht erst aufkommen lassen. Ich sehe auch kein Szenario wo man dazu gezwungen wäre.
-
SeppJ schrieb:
Du hast RAII nicht verstanden.
Geht das schon wieder los?
SeppJ schrieb:
Solche Fälle sollte man gar nicht erst aufkommen lassen.
Dann beschwer dich bei 314159265358979 und sag ihm, dass sein Design scheiße ist. Ich würds in dem konkreten Fall ganz genauso machen, weil http://en.wikipedia.org/wiki/KISS_principle.
SeppJ schrieb:
Ich sehe auch kein Szenario wo man dazu gezwungen wäre.
Die Verwendung von Ressourcen muss nicht zwangsläufig mit der Lebensdauer einer Funktion einher gehen. Dazu kannst du dir noch mal das Beispiel von 314159265358979 ansehen.
-
Natürlich könnte man statt des Flushens die File explizit closen.
-
Dann ist aber immer noch das File-Handle offen. Und es gibt Möglichkeiten Dateien so zu öffnen, dass sie kein weiteres Mal geöffnet werden können. Wenn wir aber von Ressourcen sprechen, dann meinen wir nicht nur Dateien. Zum Beispiel bei einem Drucker macht es gar kein Sinn vorher einen neuen Druckauftrag zu versenden, bevor der alte noch nicht abgeschlossen ist.
-
Dein Beispiel ist falsch. Wenn ich mehrere Seiten drucken will, lege ich die Aufträge in eine Auftrags-queue.
-
Paul Müller schrieb:
SeppJ schrieb:
Du hast RAII nicht verstanden.
Geht das schon wieder los?
Bis du es endlich verstehst
. Das ist kein Gefrickel das mal in seltenen Ausnahmefällen funktioniert. Das ist eine grundlegende Technik, die eigentlich immer für alles funktioniert (du magst exotische Ausnahmefälle konstruieren können, aber FileHandles, Drucker und vor allem Arbeitsspeicher gehören nicht dazu!).SeppJ schrieb:
Solche Fälle sollte man gar nicht erst aufkommen lassen.
Dann beschwer dich bei 314159265358979 und sag ihm, dass sein Design scheiße ist.
Ist es auch, denn seine Variablen sind nicht so lokal wie sie sein sollten:
#include <iostream> #include <fstream> #include <iomanip> int main(int argc, char** argv) { { std::ofstream os("exit.bin"); os << '\x90' << std::flush; } // os wird hiernach nie wieder gebraucht, also lokal machen. { std::ifstream is("exit.bin"); unsigned char tmp; is >> tmp; std::cout << std::hex << static_cast<unsigned>(tmp) << std::endl; } // is und tmp werden hiernach nie wieder gebraucht, also lokal machen }Zack, alle Probleme gelöst indem 4 Zeichen eingefügt wurden. Gleichzeitig gezeigt, dass man über die Programmstruktur nachgedacht hat. Und vor allem kann jetzt nirgends mehr irgendwas schiefgehen.
-
Ist das euer ernst mit den Klammern oder ein schlechter Scherz?

-
Nein dein Ansatz ist falsch. Die Auftrags-Queue ist nicht der Drucker, die Auftrags-Queue bedient nur den Drucker. Damit hält sie das Problem von dir fern, indem sie dir die Arbeit abnimmt. Aber nur weil du das Problem nicht mehr siehst, heißt das nicht, dass es nicht prinzipiell da ist.
-
Über den Ansatz mit den Klammern hab ich auch schon nachgedacht. Hab ihn aber wieder verworfen, weil man ja auch noch Variablen gebrauchen könnte, die auf diesem Weg durch ihre Initialisierung in einen anderen Block rutschen.
-
Paul Müller schrieb:
Über den Ansatz mit den Klammern hab ich auch schon nachgedacht. Hab ihn aber wieder verworfen, weil man ja auch noch Variablen gebrauchen könnte, die auf diesem Weg durch ihre Initialisierung in einen anderen Block rutschen.
Was meinst du mit Variablen, die durch ihre Initialisierung in einen anderen Block rutschen?
@314159265358979 :
Natürlich ist der Ansatz ernst gemeint - scopes eingefügt, Objekte werden zerstört wenn sie nicht mehr gebraucht werden und dabei Resourcen freigegeben -> RAII umgesetzt.
-
{ std::ifstream is("exit.bin"); unsigned char tmp; is >> tmp; std::cout << std::hex << static_cast<unsigned>(tmp) << std::endl; } // is und tmp werden hiernach nie wieder gebraucht, also lokal machenWas ist, wenn ich tmp später doch noch brauche? Dann bleibt mir ja gar nichts anderes übrig, als tmp außerhalb des Scopes zu deklarieren. Und damit hätte ich ja kein RAII mehr. Auch wenn RAII in Verbindung mit tmp in jedem Fall verletzt wird, so beschränkt sich die Variante von SeppJ zumindest auf eine minimal mögliche Verletzung.
-
Paul Müller schrieb:
Was ist, wenn ich tmp später doch noch brauche? Dann bleibt mir ja gar nichts anderes übrig, als tmp außerhalb des Scopes zu deklarieren.
Genau.
Und damit hätte ich ja kein RAII mehr.
Wieso nicht?
Faustregel: RAII funktioniert und hilft immer. Gegenbeispiele musst du schon sehr gezielt konstruieren. Hier sehe ich nicht, was du für ein Problem haben könntest.
-
Ich seh den Zusammenhang nicht ganz. Inwiefern würde eine Definition (nicht Deklaration) von tmp im übergeordneten scope (also der main-Funktion) das RAII-Idiom verletzen?
Die STL macht gebrauch von der RAII-Technik - beim file-stream-template wird eben im Destruktor close() aufgerufen. Dann macht es allerdings wenig Sinn, wenn ich die Lebensdauer eines filestream-Objekts unnötig verlänger - im schlimmsten Fall leg ich es global an.
Also versucht man Objekte möglichst lokal zu halten und genau das geschieht hier doch.
-
struct Foo { Foo() Foo(std::istream &); std::istream & operator >> (std::istream &); }; int main() { Foo foo; // Initialisierung { std::cin >> foo; // Zuweisung } Foo bar(std::cin); // Initialisierung }Oder wo ist mein Denkfehler?
-
std::cin ist ein Objekt, kein Typ.
{ std::cin >> foo; // Zuweisung }Hier wird also kein Konstruktor oder Destruktor aufgerufen, folglich findet kein RAII statt.
-
Genau das steht doch dort?
-
Dann schreib doch bitte was dein Beispiel zeigen sollte. So wie du es gemacht hast, macht die Einführung eines weiteren Scopes natürlich keinen Sinn...
-
Es geht ja auch gar nicht um den Scope, sondern um RAII. Sorry wenn dich das verwirrt hat.
-
Paul Müller schrieb:
Es geht ja auch gar nicht um den Scope, sondern um RAII. Sorry wenn dich das verwirrt hat.
Ich sehe auch nicht, was das mit RAII zu tun haben soll. Und die Kommentare helfen nicht. Außerdem compiliert das nicht einmal.
-
Es geht ja auch gar nicht um den Scope, sondern um RAII.
Dein Beispiel hat nur, wie ich erklärt habe, nichts mit RAII zu tun.
RAII ist doch ganz einfach: Im Konstruktor fordere ich Ressourcen an (z.B. mit
new) und im Destruktoren gebe ich die Ressourcen wieder frei (z.B. mitdelete). Da die Destruktoren in C++ deterministisch sind, kann man sicher sein, dass sobald ein Objekt den Scope verlässt, der Destruktor aufgerufen wird und dadurch die Ressourcen freigegeben werden. Nur so kann man dann auch richtige Exceptionsicherheit bekommen.Zur Benutzung von std::fstream::close():
Diese macht nur Sinn, wenn man das Objekt für eine andere Datei wiederverwenden möchte, statt ein neues dafür anzulegen. In so einem Fall muss vorher close() aufgerufen werden, da sonst open() fehlschlägt.