Exceptions im statisch aufgerufenem Konstruktor
-
Exception innerhalb des Konstruktors.
Das führt doch immer zu std::abort(), da die Exception nicht gefangen werden kann.Meinst du nicht eher eine Exception innerhalb des Destruktors. Innerhalb des Konstruktors sind Exceptions doch kein Problem.
-
> Innerhalb des Konstruktors sind Exceptions doch kein Problem.
Gewöhnlich nicht, nein. Aber hier schon. Schau mal auf Zeile 17. Das ist ein Konstruktoraufruf. Nur, der findet im globalen Scope statt (!).
D.h., dass noch vor main() Code ausgeführt wird. Wenn ich in diesem Code eine Exception werfe, kann sie nicht gefangen werden, und das endet immer in std::abort().
-
Ich sehe folgende Möglichkeiten:
a) du lässt es dabei, dass abort() aufgerufen wird - wenn es etwas sehr wichtiges ist, ohne das das Programm eh nicht laufen kann, dann reichts, da noch ne Fehlermeldung auszuspucken (function scope try/catch um den Ctor) und dann das Programm ins abort laufen zu lassen.
b) Du rufst den Ctor später auf - die Methoden, die sich drauf verlassen müssen, dass Startup() bereits aufgerufen wurde, rufen eine Statische Methode von A auf, die die Initialisierung übernimmt:
class A { A() {Startup();} ~A() {Cleanup()} public: static void initialize() { static A const a; } }; void some_foo_that_needs_startup() { A::initialize(); //do the foo }So wird die Exception erst geworfen, wenn das erste mal eine Funktion aufgerufen wird, die initialize() aufruft. Alle weiteren Aufrufe von initialize() machen nichts mehr. Abgeräumt wird das Objekt wie gehabt nach Beendigung der main().
PS: über Threadsafety hab ich mir im Moment keine Gedanken gemacht...
-
Besonders der 2. Vorschlag klingt echt super. Den werde ich umsetzten können.

> PS: über Threadsafety hab ich mir im Moment keine Gedanken gemacht...
Das spielt zum Glück an dem Punkt keine Rolle, da die API-Funktion threadsafe ist.

Danke
-
Jodocus schrieb:
> PS: über Threadsafety hab ich mir im Moment keine Gedanken gemacht...
Das spielt zum Glück an dem Punkt keine Rolle, da die API-Funktion threadsafe ist.

Danke
Ob die API Funktion thread-safe ist oder nicht, darum geht's nicht unbedingt.
Verwende einfach boost::call_once um die Init-Funktion aufzurufen.
-
Ich hab das ganze über ein Singleton gelöst. Also wenn ein Socket erzeugt wird, hole ich mir die Instanz. Diese wird dadurch erst mit dem ersten Socket erstellt und nicht immer, so wie bei dir. Diese Instanz lebt dann bis zum Programm-Schluss. Man könnte jetzt noch über einen Referenz-Zähler die cleanup-Funktion triggern, aber ich denke das wird egal sein, wann diese gerufen wird. Mir ging es nur darum diesen Mechanismus nicht selber machen zu müssen.
-
> darum geht's nicht unbedingt.
Worum denn dann? Was kann denn schon passieren?
-
In diesem einfachen Beispiel vermutlich nicht viel.
"Korrekt" ist es IMO dennoch nicht.EDIT: ich halte die Frage "was kann denn schon passieren" übrigens für den komplett falschen Ansatz, um nicht zu sagen: für dumm und gefährlich.
-
> In diesem einfachen Beispiel vermutlich nicht viel.
Ich behaupte mal: nichts.

> "Korrekt" ist es IMO dennoch nicht.
Wieso?
> ich halte die Frage "was kann denn schon passieren" übrigens für den komplett falschen Ansatz
Ich programmiere exceptionsicher - aber hier kann einfach nichts passieren.
-
Jodocus schrieb:
> In diesem einfachen Beispiel vermutlich nicht viel.
Ich behaupte mal: nichts.

Die offensichtliche Variante ist, dass es passieren könnte, dass der Konstruktor von A 2x concurrent ausgeführt wird. OK, die Funktion die im Konstruktor ausgefürht wird ist thread-safe, soll sein. Aber wer sagt dass der Compiler für die Initialisierung von statischen Variablen Coder erzeugt der thread-safe ist? Der Standard schreibt das nicht vor.
Je nachdem wie der Compiler die Initialisierung von statics implementiert (und auf welcher CPU das ganze läuft), könnte es auch passieren, dass A::a gar nicht initialisiert wird, wenn A::initialize gleichzeitig in zwei Threads ausgeführt wird.
Daher ist es nicht korrekt. So einfach ist das.