Try-catch flutuante
Caloni, 2008-04-03 computer ccpp blogEsse detalhe da linguagem quem me fez descobrir foi o Yorick, que costuma comentar no blogue e tive o prazer de conhecer no 4o. EPA-CCPP.
É possível, apesar de bizarro, colocar um bloco try-catch em torno da lista de inicialização de variáveis de um construtor. Essa característica da linguagem permite que possamos capturar alguma exceção lançada por algum construtor de algum membro da classe. A construção em código ficaria no estilo abaixo:
Class::Class() try : initialization-list
{
// Class constructor body
}
catch(...) // note: this IS right!
{
// do something about
// just like "throw" over here
}
Apesar dessa capacidade, não conseguimos parar o lançamento da exceção. Após seu lançamento, caímos no bloco catch abaixo do corpo do construtor e a exceção é lançada novamente, como se houvesse uma intrução throw no final do catch.
O exemplo abaixo demonstra um código de uma classe que captura a exceção durante a inicialização dos membros. Na seguida o catch da função main é executada, provando que a exceção de fato não é "salva" no primeiro bloco.
#include <iostream>
/* This class explodes */
class Explode
{
public:
Explode(int x)
{
m_x = x;
throw x;
}
void print()
{
std::cout << "The number: " << m_x << std::endl;
}
private:
int m_x;
};
/* This class is going to be exploded */
class Victim
{
public:
Victim() try : m_explode(5)
{
std::cout << "You're supposed to NOT seeing this...\n";
}
catch(...)
{
std::cerr << "Something BAD hapenned\n";
std::cerr << "We're going to blow up\n";
// just like 'throw' over here
}
void print()
{
m_explode.print();
}
private:
Explode m_explode;
};
int main()
{
try
{
Victim vic;
}
catch(...)
{
std::cerr << "Something BAD BAD happenned...\n";
}
}
Testei esse código nos seguintes compiladores:
A saída esperada é a seguinte:
Something BAD hapenned We're going to blow up Something BAD BAD happenned...
2008-04-10 Alberto Fabiano:
Meu caro,
Só por curiosidade, eu também fiz o teste nos seguintes compiladores:
[]s
2008-04-11 Thiago Adams:
Também pode ser usado assim:
void f() try
{
throw 1;
//throw "";
}
catch (int) {
throw;
}
catch (...) {
std::terminate();
}
Que poderia simular algo assim:
void f() throw(int)
{
}
2008-04-13 Caloni:
Alberto: valeu pelos testes! É bom saber que existem outros compiladores tão bons quanto o GCC e o VC no mercado.
Thiago: isso sim é bem esquisito! Te confesso que nem entendi direito o uso desse exemplo.
2008-04-14 Thiago R Adams:
Quando uma função possui a especificação das exceções significa que ela só pode lançar aquelas exceções. Caso seja lançado outra, o std::unexpected(); é chamado. O compilador VC++ não obedece essa especificação do C++. Mas é possível gerar o código na mão, usando aquela sintaxe com o try.
Então por exemplo:
void f() throw(int); //num compilador que obedece o padrao
É equivalente a fazer "na mão":
void f() try
{
//algo...
}
catch (int) {
throw;
}
catch (...) {
std::unexpected()
}
Este é outro uso curioso do try que eu resolvi comentar aqui.
2008-04-16 PopolonY2k:
Grande blog...
... Caloni, não o conhecia anteriormente e vejo que darei vários "pitacos" por aqui sempre que puder.
Sobre o bloco try catch(...) em inicialização de variáveis e objetos em construtores, vale ressaltar o que o amigo Thiago Adams citou acima, que é o uso em qualquer tipo de função de C++, mas alguns cuidados devem ser tomados conforme reportado no padrão ANSI de C++ proposto em 1998.
Sobre não ter funcionado em alguns compiladores reportados por você, como o Visual Studio 6 - VC++ 6.0, Borland C++ Builder 5 e o Borland Studio Developer Studio 4, deve deixo registrado aqui que a proposta de try catch na inicialização de funções veio na versão final da proposta do padrão ANSI para C++ em 1998, portanto compiladores, como o Visual C++ 6.O (Visual Studio 6) e Borland C++ Builder 5 já estavam no mercado e portanto não existia maneira de que os mesmos respeitassem a nova sintaxe proposta pelo ANSI.
Segue um artigo de referência no Dr. Dobbs (2026-03-23 Dr. Dobbs no more).
Um abraço,
PopolonY2k
PlanetaMessenger.org