¿Cómo funciona lanzar y atrapar objetos?

14

Con este código:

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;
}

Tenemos:

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

Cómo hace el catch bloque de leer -1como int&? No pudimos asignar un valor a una referencia de valor no constante.

¿Y por qué se std::coutejecuta la segunda declaración antes de la primera std::cerr?

Ghasem Ramezani
fuente
2
¿Estás seguro de que este es el resultado exacto que obtienes? La We caught an int exception with value: -1línea debe imprimirse primero.
HolyBlackCat
1
@Scheff, lo siento, tienes razón, la primera salida se redirige a error streamno standard stream.
Ghasem Ramezani
2
@ FrançoisAndrieux La razón por la que está permitido es que están sucediendo diferentes semánticas. Generalmente con un temporal no sabes lo que le va a pasar, así que se decidió permitir solo referencias constantes a temporales. Con excepciones, conocemos la vida útil del objeto y es posible que deseemos modificarlo y volver a lanzarlo a un contexto superior. Para facilitar eso, el estándar permite la unión a una referencia de valor no constante.
NathanOliver
1
@ FrançoisAndrieux throwcrea una copia (o mueve) el objeto que le pasa. La referencia se une a esa copia. Tiene sentido que la copia sea un valor.
HolyBlackCat

Respuestas:

10

Esto está bien debido a [excepto tirar] / 3

Lanzar una excepción copy-initializes ([dcl.init], [class.copy.ctor]) un objeto temporal, llamado objeto de excepción. Un valor l que denota el temporal se usa para inicializar la variable declarada en el controlador correspondiente ([except.handle]).

énfasis mío

Como puede ver, aunque es temporal, el compilador lo trata como un valor para inicializar el controlador. Debido a esto, no necesita una referencia constante.

NathanOliver
fuente
1
Pero, ¿qué pasa con el orden en que aparecen los mensajes?
Tomáš Zato - Restablece a Mónica el
8

De esta throwreferencia :

A diferencia de otros objetos temporales, el objeto de excepción se considera un argumento lvalue cuando se inicializan los parámetros de la cláusula catch, por lo que puede ser capturado por la referencia lvalue, modificado y relanzado.

Entonces, aunque el "objeto" es temporal, sigue siendo un valor l y, como tal, puede atraparlo por referencia.

Algún tipo programador
fuente