Por que isso:
#include <string>
#include <iostream>
using namespace std;
class Sandbox
{
public:
Sandbox(const string& n) : member(n) {}
const string& member;
};
int main()
{
Sandbox sandbox(string("four"));
cout << "The answer is: " << sandbox.member << endl;
return 0;
}
Dê saída de:
A resposta é:
Ao invés de:
A resposta é: quatro
cout << "The answer is: " << Sandbox(string("four")).member << endl;
, seria garantido que funcionaria.SandBox::member
é lida, a string temporária ainda está ativa .string("four")
é destruído no final da expressão completa e não depois que oSandbox
construtor sai? A resposta de Potatoswatter diz que UmRespostas:
Somente referências locais
const
prolongam a vida útil.O padrão especifica esse comportamento em §8.5.3 / 5, [dcl.init.ref], a seção sobre inicializadores de declarações de referência. A referência no seu exemplo está vinculada ao argumento do construtor
n
e se torna inválida quando o objeton
está fora do escopo.A extensão da vida útil não é transitiva por meio de um argumento de função. §12.2 / 5 [class.temporary]:
fonte
member
está vinculado a um temporário, porque a inicializaçãomember
comn
meios para vincularmember
ao mesmo objeton
está vinculada e, de fato, é um objeto temporário nesse caso.const
quaificador.Aqui está a maneira mais simples de explicar o que aconteceu:
Em main (), você criou uma string e a passou para o construtor. Essa instância de cadeia existia apenas dentro do construtor. Dentro do construtor, você designou um membro para apontar diretamente para esta instância. Quando o escopo deixou o construtor, a instância da string foi destruída e o membro apontou para um objeto de string que não existia mais. Fazer com que Sandbox.member aponte para uma referência fora de seu escopo não manterá essas instâncias externas no escopo.
Se você deseja corrigir o seu programa para exibir o comportamento desejado, faça as seguintes alterações:
Agora o temp ficará fora do escopo no final de main () em vez de no final do construtor. No entanto, isso é uma prática ruim. Sua variável de membro nunca deve ser uma referência a uma variável que existe fora da instância. Na prática, você nunca sabe quando essa variável ficará fora do escopo.
O que eu recomendo é definir Sandbox.member como um
const string member;
Isso copiará os dados do parâmetro temporário na variável membro em vez de atribuir a variável membro como o próprio parâmetro temporário.fonte
const string & temp = string("four"); Sandbox sandbox(temp); cout << sandbox.member << endl;
ainda funcionará?const string &temp = string("four");
dá o mesmo resultado queconst string temp("four");
, a menos que você usadecltype(temp)
especificamenteHowever, this is bad practice.
- porque? Se o temp e o objeto contido usam armazenamento automático no mesmo escopo, não é 100% seguro? E se você não fizer isso, o que faria se a string fosse muito grande e muito cara para copiar?Tecnicamente falando, não é necessário que esse programa produza algo na saída padrão (que é um fluxo em buffer para começar).
O
cout << "The answer is: "
bit será emitido"The answer is: "
no buffer do stdout.Em seguida, o
<< sandbox.member
bit fornecerá a referência pendenteoperator << (ostream &, const std::string &)
, que invoca um comportamento indefinido .Por isso, nada garante que isso aconteça. O programa pode funcionar aparentemente bem ou pode falhar sem liberar o stdout - o que significa que o texto "A resposta é:" não aparece na tela.
fonte
"The answer is: "
será escrito em qualquer lugar.Como sua sequência temporária ficou fora do escopo quando o construtor Sandbox retornou e a pilha ocupada por ela foi recuperada para outros fins.
Geralmente, você nunca deve reter referências a longo prazo. As referências são boas para argumentos ou variáveis locais, nunca para membros da classe.
fonte
você está se referindo a algo que desapareceu. O seguinte funcionará
fonte