Isso é um pouco subjetivo, eu acho; Não tenho certeza se a opinião será unânime (já vi muitos trechos de código em que as referências são retornadas).
De acordo com um comentário sobre essa pergunta que acabei de fazer, em relação à inicialização de referências , o retorno de uma referência pode ser ruim porque, como eu entendo, fica mais fácil deixar de excluí-la, o que pode levar a vazamentos de memória.
Isso me preocupa, pois tenho seguido exemplos (a menos que esteja imaginando coisas) e feito isso em poucos lugares ... Entendi mal? Isso é mau? Se sim, quão mal?
Eu sinto que, por causa do meu pacote misto de ponteiros e referências, combinado com o fato de eu ser novo em C ++, e total confusão sobre o que usar quando, meus aplicativos devem ser um inferno de vazamento de memória ...
Além disso, entendo que o uso de ponteiros inteligentes / compartilhados geralmente é aceito como a melhor maneira de evitar vazamentos de memória.
Respostas:
Em geral, retornar uma referência é perfeitamente normal e acontece o tempo todo.
Se você diz:
Isso é todo tipo de mal. A pilha alocada
i
desaparecerá e você está se referindo a nada. Isso também é mau:Porque agora o cliente precisa fazer o estranho:
Observe que as referências rvalue ainda são apenas referências; portanto, todos os aplicativos inválidos permanecem os mesmos.
Se você deseja alocar algo que vive além do escopo da função, use um ponteiro inteligente (ou, geralmente, um contêiner):
E agora o cliente armazena um ponteiro inteligente:
Referências também são boas para acessar itens em que você sabe que a vida está sendo mantida aberta em um nível superior, por exemplo:
Aqui sabemos que não há problema em retornar uma referência a
i_
porque o que quer que esteja nos chama gerencia o tempo de vida da instância da classe, e assim permanecerái_
pelo menos por tanto tempo.E, claro, não há nada errado com apenas:
Se o tempo de vida útil for deixado para o chamador, e você está apenas computando o valor.
Resumo: não há problema em retornar uma referência se a vida útil do objeto não terminar após a chamada.
fonte
return new int
.Não. Não, não, mil vezes não.
O que é mau é fazer referência a um objeto alocado dinamicamente e perder o ponteiro original. Quando você é
new
um objeto, assume uma obrigação de ter uma garantiadelete
.Mas dê uma olhada, por exemplo, em
operator<<
: isso deve retornar uma referência, ounão vai funcionar.
fonte
Você deve retornar uma referência a um objeto existente que não desaparece imediatamente e para o qual não pretende transferir a propriedade.
Nunca retorne uma referência a uma variável local ou algo parecido, porque ela não estará lá para ser referenciada.
Você pode retornar uma referência a algo independente da função, que não espera que a função de chamada assuma a responsabilidade de excluir. Este é o caso do típico
operator[]
função .Se você estiver criando algo, retorne um valor ou um ponteiro (regular ou inteligente). Você pode retornar um valor livremente, pois ele está entrando em uma variável ou expressão na função de chamada. Nunca retorne um ponteiro para uma variável local, pois ela desaparecerá.
fonte
As respostas não são satisfatórias, então adicionarei meus dois centavos.
Vamos analisar os seguintes casos:
Uso incorreto
Isso é obviamente erro
Uso com variáveis estáticas
Isso está certo, porque variáveis estáticas existem durante toda a vida útil de um programa.
Isso também é bastante comum ao implementar o padrão Singleton
Uso:
Operadores
Os contêineres de biblioteca padrão dependem muito do uso de operadores que retornam referências, por exemplo
pode ser usado no seguinte
Acesso rápido a dados internos
Há momentos em que & pode ser usado para acesso rápido a dados internos
com o uso:
No entanto, isso pode levar a armadilhas como esta:
fonte
true
:If((a*b) == (c*d))
Container::data()
implementação deve lerreturn m_data;
Isso não é mau. Como muitas coisas no C ++, é bom se usado corretamente, mas há muitas armadilhas que você deve estar ciente ao usá-lo (como retornar uma referência a uma variável local).
Há coisas boas que podem ser alcançadas com ele (como map [name] = "olá mundo")
fonte
map[name] = "hello world"
?HashMap<String,Integer>
em Java? : PNão é verdade. Retornar uma referência não implica em semântica de propriedade. Ou seja, apenas porque você faz isso:
... não significa que agora você possui a memória mencionada por v;
No entanto, este é um código horrível:
Se você estiver fazendo algo assim porque "você não precisa de um ponteiro nessa instância", então: 1) simplesmente desreferencie o ponteiro se precisar de uma referência e 2) você acabará precisando do ponteiro, porque precisa corresponder a um novo com uma exclusão e você precisa de um ponteiro para chamar a exclusão.
fonte
Existem dois casos:
referência const - boa idéia, às vezes, especialmente para objetos pesados ou classes proxy, otimização do compilador
referência não-const - idéia ruim, às vezes, quebra encapsulamentos
Ambos compartilham o mesmo problema - podem apontar para um objeto destruído ...
Eu recomendaria o uso de ponteiros inteligentes para muitas situações em que você precisa retornar uma referência / ponteiro.
Além disso, observe o seguinte:
Existe uma regra formal - o Padrão C ++ (seção 13.3.3.1.4, se você estiver interessado) declara que um temporário só pode ser vinculado a uma referência const - se você tentar usar uma referência não const, o compilador deve sinalizar isso como um erro.
fonte
Não apenas não é mau, como às vezes é essencial. Por exemplo, seria impossível implementar o operador [] do std :: vector sem usar um valor de retorno de referência.
fonte
operator[]
para um contêiner sem usar uma referência ... estd::vector<bool>
faz. (E cria uma verdadeira bagunça no processo)::std::vector<bool>
você mencionou).std::vector<T>
no código do modelo está quebrado, seT
possívelbool
, porquestd::vector<bool>
tem um comportamento muito diferente de outras instanciações. É útil, mas deveria ter recebido seu próprio nome e não uma especializaçãostd::vector
.Além da resposta aceita:
Eu diria que este exemplo não está bem e deve ser evitado, se possível. Por quê? É muito fácil terminar com um referência pendente .
Para ilustrar o ponto com um exemplo:
entrar na zona de perigo:
fonte
A referência de retorno geralmente é usada na sobrecarga do operador em C ++ para Objeto grande, pois o retorno de um valor precisa de operação de cópia. (na sobrecarga do perator, geralmente não usamos ponteiro como valor de retorno)
Mas a referência de retorno pode causar problemas de alocação de memória. Como uma referência ao resultado será eliminada da função como uma referência ao valor de retorno, o valor de retorno não pode ser uma variável automática.
se você quiser usar referência de retorno, poderá usar um buffer de objeto estático. por exemplo
Dessa forma, você pode usar a referência retornada com segurança.
Mas você sempre pode usar ponteiro em vez de referência para retornar valor em functiong.
fonte
Eu acho que usar referência como valor de retorno da função é muito mais direto do que usar ponteiro como valor de retorno da função. Em segundo lugar, seria sempre seguro usar a variável estática à qual o valor de retorno se refere.
fonte
O melhor é criar um objeto e passá-lo como parâmetro de referência / ponteiro para uma função que aloca essa variável.
Alocar um objeto na função e retorná-lo como uma referência ou ponteiro (porém, o ponteiro é mais seguro) é uma má idéia, pois libera memória no final do bloco de funções.
fonte
A função getPtr pode acessar a memória dinâmica após a exclusão ou mesmo um objeto nulo. O que pode causar exceções de acesso incorreto. Em vez disso, getter e setter devem ser implementados e o tamanho verificado antes de retornar.
fonte
A função como lvalue (também conhecido como retorno de referências não const) deve ser removida do C ++. É terrivelmente pouco intuitivo. Scott Meyers queria um minuto () com esse comportamento.
o que não é realmente uma melhoria
O último ainda faz mais sentido.
Sei que a função como lvalue é importante para os fluxos de estilo C ++, mas vale ressaltar que os fluxos de estilo C ++ são terríveis. Eu não sou o único que pensa isso ... Lembro-me de que Alexandrescu tinha um grande artigo sobre como fazer melhor, e acredito que o boost também tentou criar um método de E / S seguro de tipo melhor.
fonte
vector::operator[]
por exemplo. Você prefere escreverv.setAt(i, x)
ouv[i] = x
? Este último é MUITO superior.v.setAt(i, x)
qualquer momento. É MUITO superior.Eu me deparei com um problema real, onde era realmente mau. Essencialmente, um desenvolvedor retornou uma referência a um objeto em um vetor. Isso foi ruim!!!
Os detalhes completos sobre os quais escrevi no Janurary: http://developer-resource.blogspot.com/2009/01/pros-and-cons-of-returing-references.html
fonte
Sobre código horrível:
Então, de fato, o ponteiro da memória perdeu após o retorno. Mas se você usar shared_ptr assim:
A memória não é perdida após o retorno e será liberada após a atribuição.
fonte