Ao ler esta explicação sobre lvalues e rvalues, estas linhas de código ficaram grudadas em mim:
int& foo();
foo() = 42; // OK, foo() is an lvalue
Eu tentei em g ++, mas o compilador diz "referência indefinida para foo ()". Se eu adicionar
int foo()
{
return 2;
}
int main()
{
int& foo();
foo() = 42;
}
Ele compila bem, mas executá-lo causa uma falha de segmentação . Apenas a linha
int& foo();
por si só compila e executa sem problemas.
O que este código significa? Como você pode atribuir um valor a uma chamada de função e por que não é um rvalue?
c++
function
return-by-reference
Sossisos
fonte
fonte
Respostas:
A explicação pressupõe que haja alguma implementação razoável para a
foo
qual retorna uma referência lvalue para um válidoint
.Essa implementação pode ser:
Agora, como
foo
retorna uma referência de lvalue, podemos atribuir algo ao valor de retorno, como:Isso atualizará o global
a
com o valor42
, que podemos verificar acessando a variável diretamente ou chamandofoo
novamente:fonte
Todas as outras respostas declaram uma estática dentro da função. Acho que isso pode confundi-lo, então dê uma olhada nisto:
Como
highest()
retorna uma referência, você pode atribuir um valor a ela. Quando for executado,b
será alterado para 11. Se você alterou a inicialização para quea
fosse, digamos, 8, entãoa
seria alterado para 11. Este é um código que pode realmente servir a um propósito, ao contrário dos outros exemplos.fonte
Declara uma função chamada foo que retorna uma referência a um
int
. O que esse exemplo falha em fornecer a você uma definição dessa função que você poderia compilar. Se usarmosAgora temos uma função que retorna uma referência para
bar
. como bar é,static
ele permanecerá ativo após a chamada à função, portanto, retornar uma referência a ele é seguro. Agora se fizermosO que acontece é que atribuímos 42 a,
bar
pois atribuímos à referência e a referência é apenas um apelido parabar
. Se chamarmos a função novamente comoEle imprimiria 42, já que definimos
bar
como acima.fonte
int &foo();
declara uma função chamadafoo()
com tipo de retornoint&
. Se você chamar essa função sem fornecer um corpo, provavelmente obterá um erro de referência indefinida.Em sua segunda tentativa, você forneceu uma função
int foo()
. Isso tem um tipo de retorno diferente para a função declarada porint& foo();
. Portanto, você tem duas declarações iguaisfoo
que não correspondem, o que viola a regra de definição única causando comportamento indefinido (nenhum diagnóstico necessário).Para algo que funcione, tire a declaração da função local. Eles podem levar a um comportamento silencioso e indefinido, como você viu. Em vez disso, use apenas declarações de função fora de qualquer função. Seu programa pode ser semelhante a:
fonte
int& foo();
é uma função que retorna uma referência paraint
. Sua função fornecida retornaint
sem referência.Você pode fazer
fonte
int & foo();
significa quefoo()
retorna uma referência a uma variável.Considere este código:
Este código imprime:
$ ./a.out k = 5
Porque
foo()
retorna uma referência à variável globalk
.Em seu código revisado, você está convertendo o valor retornado em uma referência, que então é inválida.
fonte
Nesse contexto, o & significa uma referência - então foo retorna uma referência a um int, ao invés de um int.
Não tenho certeza se você já trabalhou com ponteiros, mas é uma ideia semelhante, você não está realmente retornando o valor da função - em vez disso, você está passando as informações necessárias para encontrar o local na memória onde int é.
Portanto, para resumir, você não está atribuindo um valor a uma chamada de função - você está usando uma função para obter uma referência e, em seguida, atribuindo o valor referenciado a um novo valor. É fácil pensar que tudo acontece ao mesmo tempo, mas na realidade o computador faz tudo em uma ordem precisa.
Se você está se perguntando - o motivo de estar obtendo um segfault é porque está retornando um literal numérico '2' - então é o erro exato que você obteria se definisse um const int e depois tentasse modificá-lo valor.
Se você ainda não aprendeu sobre ponteiros e memória dinâmica, recomendo isso primeiro, pois há alguns conceitos que acho difíceis de entender, a menos que você os aprenda todos de uma vez.
fonte
O código de exemplo na página vinculada é apenas uma declaração de função fictícia. Não compila, mas se você tivesse alguma função definida, funcionaria de maneira geral. O exemplo significava "Se você tivesse uma função com esta assinatura, poderia usá-la assim".
Em seu exemplo,
foo
está claramente retornando um lvalue com base na assinatura, mas você retorna um rvalue que é convertido em um lvalue. Isso está claramente determinado a falhar. Você poderia fazer:e teria sucesso alterando o valor de x, ao dizer:
fonte
A função que você tem, foo (), é uma função que retorna uma referência a um inteiro.
Então, digamos que originalmente foo retornou 5 e, mais tarde, em sua função principal, você diz
foo() = 10;
, em seguida, imprime foo, ele imprimirá 10 em vez de 5.Espero que faça sentido :)
Eu também sou novo em programação. É interessante ver perguntas como essa que te fazem pensar! :)
fonte