Como funciona o arremesso e a captura de tintas?

14

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

Nós temos:

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

Como o catchbloco é lido -1como int&? Não foi possível atribuir um valor a uma referência que não seja const lvalue.

E por que a segunda std::coutinstrução é executada antes da primeira std::cerr?

Ghasem Ramezani
fonte
2
Tem certeza de que esta é a saída exata que você obtém? A We caught an int exception with value: -1linha deve ser impressa primeiro.
21819 HolyBlackCat
11
@Scheff, desculpe, você está certo, a primeira saída é redirecionada para error streamnão standard stream.
Ghasem Ramezani
2
@ FrançoisAndrieux A razão pela qual é permitido é que existem diferentes semânticas em andamento. Geralmente, com um temporário, você não sabe o que vai acontecer, então decidiu-se permitir apenas referências constantes a temporários. Com exceções, sabemos o tempo de vida do objeto e podemos modificá-lo e retroceder para um contexto mais alto. Para facilitar isso, o padrão permite a ligação a uma referência de valor não constante.
NathanOliver
11
@ FrançoisAndrieux throwcria uma cópia (ou move) o objeto que você passa para ele. A referência se liga a essa cópia. Faz sentido que a cópia seja um valor l.
HolyBlackCat

Respostas:

10

Isso está bom por causa de [except.throw] / 3

O lançamento de uma exceção copia-inicializa ([dcl.init], [class.copy.ctor]) um objeto temporário, chamado de objeto de exceção. Um lvalue que indica o temporário é usado para inicializar a variável declarada no manipulador correspondente ([except.handle]).

ênfase minha

Como você pode ver, mesmo sendo temporário, o compilador o trata como um valor l para inicializar o manipulador. Por isso, você não precisa de uma referência const.

NathanOliver
fonte
11
Mas qual é a ordem em que as mensagens aparecem?
Tomáš Zato - Restabelece Monica
8

A partir desta throwreferência :

Diferentemente de outros objetos temporários, o objeto de exceção é considerado um argumento lvalue ao inicializar os parâmetros da cláusula catch, para que possa ser capturado pela referência lvalue, modificado e relançado.

Portanto, embora o "objeto" seja temporário, ele ainda é um valor l e, como tal, você pode capturá-lo por referência.

Algum cara programador
fonte