Ir para o conteúdo

Ponteiros vs Referências

Diferenças entre ponteiros e referências para além das evidentes e que já são mencionadas quando nos são ensinados os pormenores da linguagem, para mais informação sobre ponteiros e referências: Reference_(C++)

Existe uma diferença meramente semântica e que não é tratada pelo compilador, fica ao cargo do programador a boa aplicação desta regra. No entanto, tomando conhecimento dela ajuda bastante a escolher entre o uso de ponteiros ou referências.

Podemos dizer que um ponteiro traz uma responsabilidade associada, a responsabilidade de gerir a memória para a qual aponta. Uma função que retorna um ponteiro retorna também a responsabilidade de gestão de memória, pelo menos esta devia ser a regra, o que nem sempre é assim. Apresento um exemplo de uma classe simplificada:

class Xpto
{
private:
    ObjectX* x;
public:
    //...

    ObjectX* CreateX(){new ObjectX;}
    ObjectX& MyX(){return *x;}
};

Temos a função CreateX() que retorna um ponteiro para ObjectX e como tal deve ser interpretado como devolvendo também a responsabilidade de gerir a memória. Teremos de libertar a memória criada na função CreateX() e a classe descarta qualquer responsabilidade sobre esse assunto, a responsabilidade fica a cargo de quem chamou a função. De notar que o nome da função também é explícito nesse aspecto, mas mesmo que não o fosse o facto de retornar um ponteiro tomamos como regra geral que a responsabilidade fica desassociada da função.

A função MyX() devolve uma referência e embora seja também do tipo ObjectX, quem fez a chamada a função não deve sequer tentar efectuar um delete sobre o retorno de MyX(). A classe é o owner da memória. Nunca se deve tentar libertar memória de uma referência, embora o compilador não se prenuncie, o desastre pode acontecer em runtime.

Retornando o tipo incorrecto nas funções anteriores pode levar ao engano do programador, libertando memória que não deveria, criando ponteiros inválidos dentro da classe ou inversamente criando memory leaks.

Alguns programadores referem que retornam sempre ponteiros porque preferem trabalhar com ponteiros, sendo estes com maior potencial em relação a referências. Uma coisa não impede a outra e é péssima prática porque pode muito bem guardar uma referência num ponteiro se tal for necessário:

Xpto* x = new Xpto();
ObjectX& ox1 = x->MyX(); //guardar em ref
ObjectX* ox2= &x->MyX();  //guardar em pointer