Basicamente, um iterator serve para navegar dentro de uma coleção de dados, ou seja, vai apontar para determinado item de um conteiner (como o vector).
Primeiro, crie um vector básico assim:
int main() {
vector<string> produtos; // Importe vector
produtos.push_back("mouse");
produtos.push_back("teclado");
produtos.push_back("monitor");
produtos.push_back("gabinete");
produtos.push_back("caixa");
cout << produtos[0] << endl;
return 0;
}
Para navegarmos pelos elementos do vector, usaremos o iterator assim:
int main() {
vector<string> produtos; // Importe vector
produtos.push_back("mouse");
produtos.push_back("teclado");
produtos.push_back("monitor");
produtos.push_back("gabinete");
produtos.push_back("caixa");
vector<string>::iterator it; // Iterator
cout << produtos[0] << endl;
return 0;
}
Para retornar o primeiro elemento, usamos o método begin(), e para exibir, a variável com ponteiro, assim:
int main() {
vector<string> produtos; // Importe vector
produtos.push_back("mouse");
produtos.push_back("teclado");
produtos.push_back("monitor");
produtos.push_back("gabinete");
produtos.push_back("caixa");
vector<string>::iterator it; // Iterator
it = produtos.begin(); // Retorna o primeiro elemento do vector
cout << *it << endl; // Não esqueça do ponteiro
return 0;
}
Também podemos usar o end(), para retornar a quantidade de elementos do vector, para exibir o último elemento em si, subtraia um, assim:
it = produtos.end() - 1;
Para navegar entre todos os elementos, podemos usar as opções advance(), next() e prev() (não exclusivo de vector e iteradores, também muito usados em listas), por exemplo:
it = produtos.begin();
advance(it, 3); // Imprime o índice 3
cout << *it << endl; // Não esqueça do ponteiro
Ou o next diretamente como ponteiro, indicando quantos elementos avançaremos:
it = produtos.begin();
cout << *next(it, 2) << endl; // Não esqueça do ponteiro
O mesmo vale pro prev, usando end() ao invés de begin():
it = produtos.end();
cout << *prev(it, 1) << endl; // Não esqueça do ponteiro
E para exibir todos os elementos, podemos fazer assim:
int main() {
vector<string> produtos; // Importe vector
produtos.push_back("mouse");
produtos.push_back("teclado");
produtos.push_back("monitor");
produtos.push_back("gabinete");
produtos.push_back("caixa");
vector<string>::iterator it; // Iterator
for(it = produtos.begin(); it != produtos.end(); it++) {
cout << *it << endl;
}
return 0;
}
PS: Podemos declarar o iterator diretamente nos parâmetros do for também.
Quando criamos um código que pode gerar um erro, podemos tratá-lo colocando ele dentro de um bloco try catch. Quando o que está sendo executado dentro do try dá erro, ele pula para o bloco catch, onde podemos tratar o erro, por exemplo fechando o programa para evitar travamentos ou exibindo uma mensagem personalizada.
Vamos primeiramente, criar um vector dentro de um try catch, assim (não esqueça de importar vector pro vector e stdexcept para o try catch):
int main() {
vector<int> num(5); // Importe vector
num.at(7) = 10; // Teste posições existentes e inexistentes.
cout << num[0] << endl;
try {// Importe stdexcept
}
catch(exception &ex) { // Aqui teremos o & indicando endereço
}
return 0;
}
Nosso vector tem 5 posições, ao colocarmos uma posição inexistente no at() (por exemplo, 7), ele dará erro, como não estamos usando o try catch, disparará um aviso de erro padrão do C++ e travará o programa. Mas até o momento, nosso código não foi tratado.
Ao colocar o código errado dentro do try, ele não gerará mais esse erro, veja como fazer:
int main() {
vector<int> num(5); // Importe vector
try {// Importe stdexcept
num.at(7) = 10;
cout << num[0] << endl;
}
catch(exception &ex) {
}
return 0;
}
Note que na forma acima, o erro foi tratado, ele não foi executado por ter dado erro, mas não travou por isso. Podemos exibir uma mensagem usando o método what() do exception, por exemplo, dessa forma:
int main() {
vector<int> num(5); // Importe vector
try {// Importe stdexcept
num.at(7) = 10;
cout << num[0] << endl;
}
catch(exception &ex) {
cerr << "ERRO: " << ex.what() << endl; // cerr é usado para exibir erros, nesse caso import fstream
}
return 0;
}
Veja que ele não trava dessa forma.
Lembrando que num vector, quando adicionamos 5 posições, elas são numeradas de 0 a 4, se adicionar ou exibir uma posição inexistente (no caso, o 5), ele dará erro). Quando o código não dá erros, ele executa normalmente.
Temos ocasiões que é necessário gerarmos uma exceção de erro, para testar isso, faremos uma função nova para divisões, assim:
double dividir(double num, double dem); // Não esqueça do protótipo da função
int main() {
double n1, n2;
cout << "Digite o numerador: ";
cin >> n1;
cout << "Digite o denominador: ";
cin >> n2;
cout << dividir(n1, n2) << endl;
return 0;
}
double dividir(double num, double dem) {
return num / dem;
}
Mas como sabemos, é impossível dividir por zero, e em C++ costuma retornar o valor inf, nesse caso, vamos tratar o erro assim:
int main() {
double n1, n2;
cout << "Digite o numerador: ";
cin >> n1;
cout << "Digite o denominador: ";
cin >> n2;
cout << endl;
try {
cout << dividir(n1, n2) << endl;
}
catch(exception &ex) {
cerr << "ERRO: " << ex.what() << endl;
}
return 0;
}
Só que tem um detalhe, mesmo se dividirmos algum número por zero, ele não será passado o erro pro catch, então devemos ir na função dividir() e criar nosso próprio aviso de erro usando o throw, assim:
double dividir(double num, double dem) {
if(dem == 0) {
throw "Tentativa de divisão por ZERO";
}
return num / dem;
}
E na função principal, mudaremos o catch assim:
try {
cout << dividir(n1, n2) << endl;
}
catch(const char* msg) {
cerr << "ERRO: " << msg << endl;
}
Dessa forma, podemos criar outras exceções sem fazer mais alterações no try catch, por exemplo:
double dividir(double num, double dem) {
if(dem == 0) {
throw "Impossível a divisão por ZERO";
}
// Outra condição
if(num < dem) {
throw "Numerador Tem que Ser Maior que o Denominador!";
}
return num / dem;
}
PS: Essa condição com o throw pode ser colocada no bloco try diretamente. E também podemos ter mais de uma cláusula catch no mesmo try.