Comment fonctionnent les lancers et les saisies?

14

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

On a:

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

Comment le catchbloc lu -1comme int&? Nous n'avons pas pu attribuer de valeur à une référence de valeur non constante.

Et pourquoi la deuxième std::coutdéclaration est-elle exécutée avant la première std::cerrdéclaration?

Ghasem Ramezani
la source
2
Êtes-vous sûr que c'est la sortie exacte que vous obtenez? La We caught an int exception with value: -1ligne doit être imprimée en premier.
HolyBlackCat
1
@Scheff, Désolé, vous avez raison, La première sortie est redirigée vers error streamnon standard stream.
Ghasem Ramezani
2
@ FrançoisAndrieux La raison pour laquelle cela est autorisé est qu'il existe différentes sémantiques. En général, avec un temporaire, vous ne savez pas ce qui va lui arriver, il a donc été décidé de n'autoriser que les références const aux temporaires. À quelques exceptions près, nous connaissons la durée de vie de l'objet et nous souhaitons peut-être le modifier et le replacer dans un contexte supérieur. Afin de faciliter cela, la norme autorise la liaison à une référence de valeur non constante.
NathanOliver
1
@ FrançoisAndrieux throwcrée une copie (ou déplace) l'objet que vous lui passez. La référence se lie à cette copie. Il est en quelque sorte logique que la copie soit une valeur l.
HolyBlackCat

Réponses:

10

C'est correct à cause de [except.throw] / 3

Le lancement d'une exception initialise la copie ([dcl.init], [class.copy.ctor]) d'un objet temporaire, appelé objet d'exception. Une lvalue dénotant le temporaire est utilisée pour initialiser la variable déclarée dans le gestionnaire correspondant ([except.handle]).

mettre l'accent

Comme vous pouvez le voir, même s'il s'agit d'un fichier temporaire, le compilateur le traite comme une valeur l pour initialiser le gestionnaire. Pour cette raison, vous n'avez pas besoin d'une référence const.

NathanOliver
la source
1
Mais quel est l'ordre dans lequel les messages apparaissent?
Tomáš Zato - Réintègre Monica
8

De cette throwréférence :

Contrairement à d'autres objets temporaires, l'objet exception est considéré comme un argument lvalue lors de l'initialisation des paramètres de la clause catch, il peut donc être capturé par la référence lvalue, modifié et renvoyé.

Ainsi, même si "l'objet" est temporaire, il s'agit toujours d'une valeur l et, en tant que tel, vous pouvez l'attraper par référence.

Un mec programmeur
la source