Wie funktioniert das Werfen und Fangen von Ints?

14

Mit diesem Code:

int main()
{
    try
    {
        throw -1;
    }
    catch (int& x)
    {
        std::cerr << "We caught an int exception with value: " << x << std::endl;
    }
    std::cout << "Continuing on our merry way." << std::endl;

    return 0;
}

Wir haben:

/tmp$ ./prorgam.out
Continuing on our merry way
We caught an int exception with value: -1

Wie funktioniert der catchBlock gelesen , -1wie int&? Wir konnten einer nicht konstanten Wertreferenz keinen Wert zuweisen.

Und warum wird die zweite std::coutAnweisung vor der ersten std::cerrAnweisung ausgeführt?

Ghasem Ramezani
quelle
2
Sind Sie sicher, dass dies die genaue Ausgabe ist, die Sie erhalten? Die We caught an int exception with value: -1Zeile sollte zuerst gedruckt werden.
HolyBlackCat
1
@Scheff, Entschuldigung, Sie haben Recht, Die erste Ausgabe wird auf error streamnicht umgeleitet standard stream.
Ghasem Ramezani
2
@ FrançoisAndrieux Der Grund, warum es erlaubt ist, ist, dass es verschiedene Semantiken gibt. Im Allgemeinen wissen Sie bei einem temporären Objekt nicht, was damit passieren wird. Daher wurde beschlossen, nur konstante Verweise auf temporäre Elemente zuzulassen. Mit Ausnahmen kennen wir die Lebensdauer des Objekts und möchten es möglicherweise ändern und in einen höheren Kontext umwandeln. Um dies zu erleichtern, erlaubt der Standard die Bindung an eine nicht konstante Wertreferenz.
NathanOliver
1
@ FrançoisAndrieux throwerstellt eine Kopie (oder verschiebt) das Objekt, das Sie an das Objekt übergeben. Die Referenz ist an diese Kopie gebunden. Es macht irgendwie Sinn, dass die Kopie ein Wert ist.
HolyBlackCat

Antworten:

10

Dies ist in Ordnung wegen [außer werfen] / 3

Durch das Auslösen einer Ausnahme wird eine Kopie kopiert ([dcl.init], [class.copy.ctor]), die als Ausnahmeobjekt bezeichnet wird. Ein l-Wert, der den temporären Wert angibt, wird verwendet, um die im übereinstimmenden Handler deklarierte Variable ([außer.handle]) zu initialisieren .

Betonung meiner

Wie Sie sehen, wird es vom Compiler als temporärer Wert für die Initialisierung des Handlers behandelt, obwohl es sich um einen temporären Wert handelt. Aus diesem Grund benötigen Sie keine konstante Referenz.

NathanOliver
quelle
1
Aber wie sieht es mit der Reihenfolge aus, in der die Nachrichten erscheinen?
Tomáš Zato - Wiedereinsetzung Monica
8

Aus dieser throwReferenz :

Im Gegensatz zu anderen temporären Objekten wird das Ausnahmeobjekt beim Initialisieren der catch-Klauselparameter als lvalue-Argument betrachtet, sodass es durch lvalue-Referenz abgefangen, geändert und erneut ausgelöst werden kann.

Während das "Objekt" temporär ist, ist es immer noch ein Wert und als solcher können Sie es als Referenz abfangen.

Ein Programmierer
quelle