You are on page 1of 5

Ponteiros x Referncia C++

Prof. Wladimir Arajo Tavares


Atribuio Ponteiros int i; int * pi = &i; Referncia int i; int &ri = i; Nos duas situaes temos o seguinte:

Ambos pi e ri guardam o endereo que aponta para a localizao de i, mas a diferena est em como a referncia e os ponteiros so usados em expresses. Para atribuir o valor 4 para i nos dois casos temos: *pi = 4; ri = 4; Note que, quando usamos ponteiros, temos que utilizar a operaes de desreferenciamento usando *. Quando usamos referncia, o endereo desreferenciado de maneira implcita. O principal efeito dessa opo que os endereos no podem ser manipulados diretamente como no caso do ponteiro (aritmtica de ponteiro). Como no seguinte caso: pi++; incrementar para o prximo endereo. Isto no possvel usando refe Uma referncia deve ser obrigatoriamente inicializada enquanto um ponteiro pode no ser inicializado. Um ponteiro pode apontar para diferentes objetos durante seu tempo de vida. Uma referncia pode referenciar somente um objeto durante seu tempo de vida.
int *pi ; // ponteiro no inicializado : risco permitido

int & ri; // referncia no inializada no permitida

Vantagens da referncia O fato de no existir uma referncia nula implica que o uso de referncia pode ser mais eficiente que o uso de ponteiros. Isto acontece uma vez que no necessrio testar a validade de uma referncia antes de us-l: void printDouble(const Double & rd) { cout rd; } Ponteiros, por outro lado, devem ser geralmente ser testados se no so nulos: void printDouble(const Double * pd) { if(pd){ cout rd; } }

Quando usar ponteiros X referncia As referncias devem ser preferencialmente usadas como maneira de endereamento indireto. Em geral, elas so mais seguras que os ponteiros. Em alguns casos, a referncia a nica maneira de alcanar um resultado particular, como por exemplo, a sobrecarga de certos operadores. Considere o seguinte exemplo: enum dia{ domingo, segunda,terca,quarta,quinta,sexta,sabado }; dia d;

Suponha que ns quisssemos escrever um mtodo para sobrecarregar o operador ++ da seguinte maneira ++x; Incrementando x para o prximo dia, ns podemos escrever o seguinte cdigo: dia &operator++(dia &d) { d = (dia)(d + 1); return d; } Usando ponteiro, ns poderamos pensar na seguinte declarao deveria funcionar: Dia * operator++(dia*d); Contudo, esta sentena no ser nem mesmo compilada por que todo operador sobrecarregado deve ser ou membro de uma funo, ou ter um parmetro do tipo T, &T ou const &T onde T uma classe ou uma enumerao. No caso particular, usando referncia a nica maneira de fazer isto. Para sobrecarregar o operador ++ ps-fixo precisamos ter um cuidado maior: dia d; dia d1 = ++d; // d1 recebe o novo valor de d dia d2 = d++; //d2 recebe o valor antigo de d e d alterado Para sobrecarrega o mtodo ++ ps-fixo temos que implementar o seguinte mtodo: dia operator++(dia &d,int i); Note a diferena entre os tipos de retorno: a verso pr-fixa retorna por referncia, e a verso ps-fixa por valor. O que no imediatamente bvio, voc prestar bastante ateno na diferena entre x++ e ++x em uma atribuio; Ns podemos escrever o seguinte cdigo para operador ++ ps-fixo: dia operator++(dia &d,int x) {

dia temp = d; ++d; return temp;

Existe outra situao na qual o uso de referncia mais conveniente. Um exemplo desta situao o operador []. Este operador tipicamente precisa retornar alguma coisa que pode ser usada como alvo de uma atribuio: vector <int> v(10); //cria um vetor de inteiros tamanho 10 v[5] = 10; //o alvo desta atribuio o valor de retorno do //operador [] Se operador [] retornasse um ponteiro, o ltimo comando deveria ser escrito desta maneira: *v[5] = 10; Mas isto torna v parecido com um vetor de ponteiro. Por esta razo melhor que o operador [] retorne uma referncia. Relacionamento de C++ referncia com ponteiros As referncias so bastante usadas como interface de mtodos pblicos de uma classe. Referncia tipicamente aparece na parte externa de um objeto, e os ponteiros so usados internamente. Diretamente, relacionado como os conceitos principais de encapsulamento e abstrao de dados. Os ponteiros so bastante utilizados em parmetros de funes ou retorno de funes que precisam de um valor sentinela - uma referncia que no refere-se a nenhum objeto. A melhor maneira de fazer isso utilizando ponteiros e dando para o ponteiro NULL um significado especial. Funes antigas do C utilizam bastante ponteiros na definio da interface de funes. Todas as funes da biblioteca string.h utilizam ponteiros, uma vez que, uma cadeia de caracteres no tipo primitivo da linguagem e tem tamanho dinmico limitado utilizando um caractere especial para indicar o final de uma cadeia (\0). Por exemplo, strcpy(char* destino, char *origem) Outro exemplo de funo da biblioteca string.h que utiliza ponteiros a funo memset: void * memset(void *ptr, int value, size_t num); Usada para preencher um bloco da memria. Seta os primeiros num bytes de um bloco de memria apontado por ptr para um valor especfico. Exemplo: int m[1000];

memset(m,0,sizeof(m)); //zera todos os bytes da varivel m int v[1000][1000]; memset(v,0,sizeof(v)); //zera todos os bytes da varivel v

Notas histricas
Tony Hoare (1973) fez uma das afirmaes mais maldizente a respeito dos ponteiros: A introduo deles nas linguagens de alto nvel foi um passo para trs, do qual talvez jamais possamos nos recuperar. Mas ele tambm cometeu um pecado que ele apelidou de meu erro bilhes de dlares. Em

1965, Tony Hoare estava desenvolvendo o primeiro sistema compreensvel de tipos para uma linguagem orientada a objetos (ALGOL W). Ele queria que todos os usos de referncias fossem seguros, com o compilador checando automaticamente. Mas ento ele teve uma idia de genial: Criar uma referncia nula. Por qu? Simplesmente porque era mais fcil de implementar.
Eu chamo-lhe o meu erro bilhes de dlares. Foi a inveno da referncia nula em 1965. Naquela poca, eu estava projetando o primeiro tipo de sistema global de referncias em uma linguagem orientada a objetos (ALGOL W). Meu objetivo era assegurar que todo o uso de referncias devem ser absolutamente seguro, com a verificao realizada automaticamente pelo compilador. Mas eu no pude resistir tentao de colocar em uma referncia nula, simplesmente porque ele era to fcil de implementar. Isto levou a inmeros erros, vulnerabilidades e falhas no sistema, o que provavelmente causou um bilho de dlares de dor e danos nos ltimos quarenta anos. Nos ltimos anos, uma srie de analisadores de programa como o prefixo e PREfast na Microsoft foram utilizados para verificar as referncias, e advertir, se houver um risco que pode ser nulo. Linguagens de programao mais recentes, como Spec # introduziram declaraes de referncias no-nulo. Esta a soluo, que rejeitou, em 1965.

You might also like