Você está na página 1de 11

Aula 8 Programação defensiva, exceção e tratamento de erros.

Algumas aplicações, quando dá erro basta abortar. Outras aplicações, o programa não pode parar quando dá erro. Detecção de erros:

Durante o desenvolvimento

Durante o tempo de execução

Foguete caríssimo explodiu pois tinha um erro de programa.

O comando assert pode ser usado para detectar erros durante o desenvolvimento.

//assert1.cpp - nao verifica erro #include <iostream> #include <cassert> using namespace std; int main() { int vetor[10]; for (int i = 0; i < 15; i++) { vetor[i] = i; cout << vetor [i] << endl;

}

}

//assert2.cpp - verifica erro

//#define NDEBUG

#include <iostream> #include <cassert> using namespace std; int main() { int vetor[10]; for (int i = 0; i < 15; i++) {

assert(0<=i && i<10);

vetor[i] = i; cout << vetor [i] << endl;

}

}

Coloque no assert a invariante (condição que deve ser verdadeira para o programa executar corretamente).

Definindo NDEBUG, assert para de fazer verificações. O programa roda mais rápido. Use assert no desenvolvimento. Defina NDEBUG e recompile antes de gerar o código final. Verificação de “invariantes” dos algoritmos.

// getset1.cpp - sem deteccao de erro #include <iostream> #include <cassert> using namespace std;

class Vetor { int v[10]; public:

int get(int i) { return v[i]; } void set(int i, int valor) { v[i]=valor; }
int get(int i) { return v[i]; } void set(int i, int valor) { v[i]=valor; }

int get(int i) { return v[i]; }

int get(int i) { return v[i]; } void set(int i, int valor) { v[i]=valor; }
void set(int i, int valor) { v[i]=valor; }

void set(int i, int valor) { v[i]=valor; }

};

int main() { Vetor vetor; for (int i = 0; i < 15; i++) { vetor.set(i,i); cout << vetor.get(i) << endl;

}

}

Nota: Escrever a implementação do código dentro da definição da classe gera função inline. Mais rápido mas ocupa mais espaço de memória. Bom para pequenas funções.

Retorna um valor especial (INT_MIN e false) se acontece erro.

// getset2.cpp #include <iostream> #include <cassert> #include <climits> using namespace std;

class Vetor { static const int maximo=10; int v[maximo]; public:

int get(int i) {

if (0<=i && i<maximo) return v[i]; else return INT_MIN;
if (0<=i && i<maximo) return v[i]; else return INT_MIN;
if (0<=i && i<maximo) return v[i];

if (0<=i && i<maximo) return v[i];

else return INT_MIN;

if (0<=i && i<maximo) return v[i]; else return INT_MIN;

}

bool set(int i, int valor) {

if (0<=i && i<maximo) { v[i]=valor; return true; } else return false;
if (0<=i && i<maximo) { v[i]=valor; return true; } else return false;
if (0<=i && i<maximo) { v[i]=valor; return true; }

if (0<=i && i<maximo) { v[i]=valor; return true; }

else return false;

if (0<=i && i<maximo) { v[i]=valor; return true; } else return false;

}

};

int main() { Vetor vetor; for (int i = 0; i < 15; i++) {

if (!vetor.set(i,i)) {

cout << "Erro: Indice invalido em Vetor::set"

<< endl;

exit(1);

}

int t=vetor.get(i);

if (t==INT_MIN) {

cout << "Erro: Indice invalido em Vetor::get"

<< endl;

exit(1);

} else cout << t << endl;

}

}

Problema1: Após chamar função, tem que ficar verificando. Se main chama f que chama g que chama h que chama set/get? Todas as funções têm que verificar erro.

Problema2: Os destrutores não são chamados no caso de erro. Vazamento de recursos: arquivo aberto e não fechado, memória alocada e não desalocada, etc. Com tempo, o programa trava.

Usando throw para jogar um objeto no caso de erro.

//getset3.cpp

#include <iostream> #include <cassert> #include <string> using namespace std;

class Erro {

public:

string nome;

};

class Vetor { static const int maximo=10; int v[maximo]; public:

int get(int i) { if (0<=i && i<maximo) return v[i];

else throw(Erro{"Erro: Indice invalido em Vetor::get"});

}

void set(int i, int valor) { if (0<=i && i<maximo) { v[i]=valor; }

else throw(Erro{"Erro: Indice invalido em Vetor::set"});

}

};

int main() { Vetor vetor; for (int i = 0; i < 15; i++) { vetor.set(i,i); cout << vetor.get(i) << endl;

}

}

Usando throw para jogar um char no caso de erro.

//getset3b.cpp

#include <iostream> #include <cassert> #include <string> using namespace std;

class Vetor { static const int maximo=10; int v[maximo]; public:

int get(int i) { if (0<=i && i<maximo) return v[i];

else throw('g');

}

void set(int i, int valor) { if (0<=i && i<maximo) { v[i]=valor; }

else throw('s');

}

};

int main() { Vetor vetor; for (int i = 0; i < 15; i++) { vetor.set(i,i); cout << vetor.get(i) << endl;

}

}

Usando try

catch

para pegar um objeto jogado no erro.

//getset4.cpp

#include <iostream> #include <cassert> #include <string> using namespace std;

class Erro { public:

string mensagem;

};

class Vetor { static const int maximo=10; int v[maximo]; public:

int get(int i) { if (0<=i && i<maximo) return v[i]; else throw(Erro{"Erro: Indice invalido em Vetor::get"});

}

void set(int i, int valor) { if (0<=i && i<maximo) { v[i]=valor; } else throw(Erro{"Erro: Indice invalido em Vetor::set"});

}

};

int main() {

try {
try {

Vetor vetor; for (int i = 0; i < 15; i++) { vetor.set(i,i); cout << vetor.get(i) << endl;

}

} catch (Erro err) {

cout << err.mensagem << endl;

}

}

Note como a função main ficou simples.

Os destrutores são chamados mesmo no caso de erro. Não há vazamento de recursos.

Não interessa se main chamou f que chamou g que chamou set. O erro é pego na última função que chamou set que tem catch.

Nota1: Divisão de inteiros por zero: É um erro que não pode ser pego por try

Nota2: Divisão de ponto flutuante por zero: Dá inf ou -inf. Não é

pego por try

catch.

//getset4b.cpp

#include <iostream> #include <cassert> #include <string> using namespace std;

class Vetor { static const int maximo=10; int v[maximo]; public:

int get(int i) { if (0<=i && i<maximo) return v[i]; else throw(string{"Erro: Indice invalido em Vetor::get"});

}

void set(int i, int valor) { if (0<=i && i<maximo) { v[i]=valor; } else throw(string{"Erro: Indice invalido em Vetor::set"});

}

};

void g() { Vetor vetor; for (int i = 0; i < 15; i++) { vetor.set(i,i); cout << vetor.get(i) << endl;

}

}

void f() { g();

}

int main() { try { f(); } catch (string err) { cout << err << endl;

}

}

Se você quiser pegar todos os throw não pegos:

//getset5.cpp

#include <iostream> #include <cassert> #include <string> using namespace std;

class Erro { public:

string mensagem;

};

class Vetor { static const int maximo=10; int v[maximo]; public:

int get(int i) { if (0<=i && i<maximo) return v[i]; else throw(Erro{"Erro: Indice invalido em Vetor::get"});

}

void set(int i, int valor) { if (0<=i && i<maximo) { v[i]=valor; } else throw(Erro{"Erro: Indice invalido em Vetor::set"});

}

};

int main() { try { Vetor vetor; for (int i = 0; i < 15; i++) { vetor.set(i,i); cout << vetor.get(i) << endl;

}

}

catch (char ch) {

 
 

cout << ch << endl;

}

catch (int i) {

 
 

cout << i << endl;

 

}

catch (

)

{

 
 

cout << "Erro nao pego" << endl;

}

}

Destructor é chamado pelo throw.

//getset6.cpp - destructor e' chamado pelo throw #include <iostream> #include <cassert> #include <string> using namespace std;

class Vetor { int maximo;

int* v;
int* v;

public:

Vetor(int _maximo) { cout << "Constructor" << endl; maximo=_maximo; v=new int[maximo]; }
Vetor(int _maximo) {
cout << "Constructor" << endl;
maximo=_maximo;
v=new int[maximo];
}
~Vetor() {
cout << "Destructor" << endl;
delete[] v;
}

int get(int i) { if (0<=i && i<maximo) return v[i]; else throw(string{"Erro: Indice invalido em Vetor::get"});

}

void set(int i, int valor) { if (0<=i && i<maximo) { v[i]=valor; } else throw(string{"Erro: Indice invalido em Vetor::set"});

}

};

int main() { try {

Vetor vetor{10};

for (int i = 0; i < 15; i++) { vetor.set(i,i); cout << vetor.get(i) << endl;

}

} catch (string err) { cout << err << endl;

}

}

//getset7.cpp - usando operator overload e referência #include <iostream> #include <cassert> #include <string> using namespace std;

class Vetor { int maximo; int* v; public:

Vetor(int _maximo) { cout << "Constructor" << endl; maximo=_maximo; v=new int[maximo];

}

~Vetor() { cout << "Destructor" << endl; delete[] v;

}

int& operator[](int i) {

 
 

if (0<=i && i<maximo) return v[i];

 
 

else throw(string{"Erro: Indice invalido"});

}

 

};

int main() { try { Vetor vetor{10}; for (int i = 0; i < 15; i++) {

vetor[i]=i;

vetor[i]=i; cout << vetor[i] << endl;
cout << vetor[i] << endl;

cout << vetor[i] << endl;

}

} catch (string err) { cout << err << endl;

}

}