Este é um exemplo simplificado para ilustrar a pergunta:
class A {};
class B
{
B(A& a) : a(a) {}
A& a;
};
class C
{
C() : b(a) {}
A a;
B b;
};
Portanto, B é responsável por atualizar uma parte do C. Executei o código através do lint e ele zombou do membro de referência: lint # 1725 . Isso fala sobre cuidar das cópias e atribuições padrão o que é justo o suficiente, mas a cópia e a atribuição padrão também são ruins para os ponteiros, portanto, há pouca vantagem nisso.
Eu sempre tento usar referências onde posso, pois ponteiros nus apresentam incertezas sobre quem é responsável por excluir esse ponteiro. Prefiro incorporar objetos por valor, mas se precisar de um ponteiro, uso auto_ptr nos dados dos membros da classe que possui o ponteiro e transmito o objeto como referência.
Geralmente, eu usaria apenas um ponteiro nos dados dos membros quando o ponteiro pudesse ser nulo ou mudar. Existem outros motivos para preferir ponteiros do que referências para membros de dados?
É verdade que um objeto que contém uma referência não deve ser atribuído, pois uma referência não deve ser alterada depois de inicializada?
fonte
Respostas:
Evite membros de referência, porque eles restringem o que a implementação de uma classe pode fazer (incluindo, como você mencionou, impedindo a implementação de um operador de atribuição) e não oferecem benefícios ao que a classe pode oferecer.
Problemas de exemplo:
até C ++ 0x, de qualquer forma,edite: o C ++ agora tem construtores delegadores ).
operador etc.), mas se comporta como um ponteiro (pode oscilar) - então, por exemplo, o Google Style Guide o desencorajafonte
Minha própria regra de ouro:
fonte
Objetos raramente devem permitir atribuições e outras coisas, como comparação. Se você considerar algum modelo de negócios com objetos como 'Departamento', 'Funcionário', 'Diretor', é difícil imaginar um caso em que um funcionário será atribuído a outro.
Portanto, para objetos de negócios, é muito bom descrever os relacionamentos um para um e um para muitos como referências e não como indicadores.
E provavelmente não há problema em descrever o relacionamento um ou zero como um ponteiro.
Portanto, nenhum fator 'não podemos atribuir'.
Muitos programadores simplesmente se acostumam com ponteiros e é por isso que eles encontram qualquer argumento para evitar o uso de referência.
Ter um ponteiro como membro forçará você ou membro de sua equipe a verificar o ponteiro várias vezes antes do uso, com o comentário "just in case". Se um ponteiro pode ser zero, o ponteiro provavelmente é usado como um tipo de sinalizador, o que é ruim, pois todo objeto tem que desempenhar seu próprio papel.
fonte
Use referências quando puder e ponteiros quando precisar.
fonte
Em alguns casos importantes, a atribuição simplesmente não é necessária. Geralmente, são wrappers de algoritmo leves que facilitam o cálculo sem sair do escopo. Esses objetos são candidatos principais para membros de referência, pois você pode ter certeza de que eles sempre possuem uma referência válida e nunca precisam ser copiados.
Nesses casos, certifique-se de tornar o operador de atribuição (e geralmente também o construtor de cópias) não utilizável (herdando
boost::noncopyable
ou declarando-o privado).No entanto, como os usuários já comentaram, o mesmo não ocorre para a maioria dos outros objetos. Aqui, o uso de membros de referência pode ser um grande problema e geralmente deve ser evitado.
fonte
Como todo mundo parece estar distribuindo regras gerais, vou oferecer duas:
Nunca, nunca use referências como alunos. Eu nunca fiz isso no meu próprio código (exceto para provar a mim mesmo que estava certo nesta regra) e não consigo imaginar um caso em que o faria. A semântica é muito confusa, e realmente não é para isso que as referências foram criadas.
Sempre, sempre, use referências ao passar parâmetros para funções, exceto para os tipos básicos, ou quando o algoritmo exigir uma cópia.
Essas regras são simples e me mantiveram em boa posição. Deixo fazendo regras sobre o uso de ponteiros inteligentes (mas, por favor, não auto_ptr) como membros da classe para outras pessoas.
fonte
Sim para: É verdade dizer que um objeto que contém uma referência não deve ser atribuído, pois uma referência não deve ser alterada depois de inicializada?
Minhas regras práticas para membros de dados:
fonte
Sim. Legibilidade do seu código. Um ponteiro torna mais óbvio que o membro é uma referência (ironicamente :)) e não um objeto contido, porque quando você o usa, é necessário desassociá-lo. Sei que algumas pessoas pensam que é antiquado, mas ainda acho que isso simplesmente evita confusão e erros.
fonte
Aconselho contra os membros de dados de referência, porque você nunca sabe quem irá derivar de sua classe e o que eles podem querer fazer. Eles podem não querer usar o objeto referenciado, mas, sendo uma referência, você os forçou a fornecer um objeto válido. Fiz isso comigo o suficiente para parar de usar membros de dados de referência.
fonte
Se eu entendi a pergunta corretamente ...
Referência como parâmetro de função em vez de ponteiro: Como você apontou, um ponteiro não deixa claro quem é o proprietário da limpeza / inicialização do ponteiro. Prefira um ponto compartilhado quando desejar um ponteiro, ele faz parte do C ++ 11 e um fraco_ptr quando a validade dos dados não for garantida durante a vida útil da classe que aceita os dados apontados .; também parte do C ++ 11. O uso de uma referência como parâmetro de função garante que a referência não seja nula. Você precisa subverter os recursos de idioma para contornar isso, e não nos importamos com codificadores de canhão soltos.
Referência aa variável de membro: Como acima, em relação à validade dos dados. Isso garante que os dados apontados e referenciados são válidos.
Mover a responsabilidade da validade variável para um ponto anterior no código não apenas limpa o código posterior (a classe A no seu exemplo), mas também deixa claro para a pessoa que está usando.
No seu exemplo, que é um pouco confuso (eu realmente tentaria encontrar uma implementação mais clara), o A usado por B é garantido por toda a vida útil do B, já que B é um membro de A, portanto, uma referência reforça isso. e é (talvez) mais claro.
E, apenas no caso (que é uma probabilidade muito baixa, pois não faria sentido no contexto de seu código), outra alternativa, usar um parâmetro A não referenciado e sem ponteiro, copiaria A e tornaria o paradigma inútil - I realmente não acho que você quis dizer isso como uma alternativa.
Além disso, isso também garante que você não poderá alterar os dados mencionados, onde um ponteiro pode ser modificado. Um ponteiro const funcionaria apenas se o ponteiro / referência aos dados não fosse mutável.
Os ponteiros são úteis se não for garantido que o parâmetro A para B seja definido ou possa ser reatribuído. E, às vezes, um ponteiro fraco é muito detalhado para a implementação, e um bom número de pessoas não sabe o que é um fraco_ptr ou apenas as detesta.
Rasgue esta resposta, por favor :)
fonte