O código a seguir (func1 ()) está correto se tiver que retornar i? Lembro-me de ter lido em algum lugar que há um problema ao retornar a referência a uma variável local. Como é diferente de func2 ()?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int& i = * new int;
Respostas:
Este snippet de código:
não funcionará porque você está retornando um alias (uma referência) para um objeto com uma vida útil limitada ao escopo da chamada de função. Isso significa que uma vez que
func1()
retorna,int i
morre, tornando a referência retornada da função inútil porque agora se refere a um objeto que não existe.A segunda versão funciona porque a variável é alocada no armazenamento gratuito, o que não é limitado ao tempo de vida da chamada de função. No entanto, você é responsável por
delete
fazer o envioint
.Normalmente, você envolveria o ponteiro em alguma classe RAII e / ou uma função de fábrica para que não precisasse fazer
delete
isso sozinho.Em qualquer caso, você pode simplesmente retornar o valor em si (embora eu saiba que o exemplo que você forneceu provavelmente foi inventado):
Observe que é perfeitamente normal retornar objetos grandes da mesma forma que
func3()
retorna valores primitivos porque quase todo compilador hoje em dia implementa alguma forma de otimização de valor de retorno :Curiosamente, vincular um temporário a uma referência const é perfeitamente C ++ legal .
fonte
int* p = func2(); delete p;
Agora, quando você excluiu 'p', isso significa que a memória alocada "dentro" dafunc2()
definição da função também foi excluída?func2()
e liberada externamente na próxima linha. No entanto, é uma forma bastante sujeita a erros de lidar com a memória, como eu disse que você usaria alguma variante do RAII. A propósito, você parece estar aprendendo C ++. Eu recomendo pegar um bom livro introdutório ao C ++ para aprender. Além disso, para referência futura, se você tiver alguma dúvida, poderá postá-la no Stack Overflow. Os comentários não são feitos para fazer perguntas totalmente novas.Uma variável local é a memória na pilha, essa memória não é automaticamente invalidada quando você sai do escopo. De uma função mais aninhada (mais acima na pilha de memória), é perfeitamente seguro acessar essa memória.
Uma vez que a função retorna e termina, as coisas ficam perigosas. Normalmente, a memória não é excluída ou substituída quando você retorna, o que significa que a memória naquele endereço ainda contém seus dados - o ponteiro parece válido.
Até que outra função acumule a pilha e a substitua. É por isso que isso pode funcionar por um tempo - e então parar repentinamente de funcionar depois que um conjunto de funções particularmente profundamente aninhado, ou uma função com um tamanho realmente grande ou muitos objetos locais, atinge aquela pilha de memória novamente.
Pode até acontecer que você alcance a mesma parte do programa novamente e sobrescreva sua antiga variável de função local com a nova variável de função. Tudo isso é muito perigoso e deve ser fortemente desencorajado. Não use ponteiros para objetos locais!
fonte
É bom lembrar essas regras simples, e elas se aplicam a parâmetros e tipos de retorno ...
Há uma hora e um lugar para cada um, portanto, certifique-se de conhecê-los. As variáveis locais, como você mostrou aqui, são apenas isso, limitadas ao tempo em que estão ativas localmente no escopo da função. Em seu exemplo, ter um tipo de retorno de
int*
e retornar&i
teria sido igualmente incorreto. Você estaria melhor nesse caso fazendo isso ...Fazer isso alteraria diretamente o valor do parâmetro passado. Considerando que este código ...
não faria. Isso apenas mudaria o valor de
oValue
local para a chamada de função. A razão para isso é porque você na verdade estaria alterando apenas uma cópia "local"oValue
, e nãooValue
ela mesma.fonte