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 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;
}
bool set(int i, int valor) {
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 {
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...catch.
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;
public:
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;
cout << vetor[i] << endl;
}
} catch (string err) {
cout << err << endl;
}
}

Você também pode gostar