Pourquoi cela:
#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;
}
Donner la sortie de:
La réponse est:
Au lieu de:
La réponse est: quatre
cout << "The answer is: " << Sandbox(string("four")).member << endl;
, cela fonctionnera à coup sûr.SandBox::member
est lu, la chaîne temporaire est toujours vivante .string("four")
est détruit à la fin de l'expression complète, et non après la fermeture duSandbox
constructeur? La réponse de Potatoswatter dit qu'une liaison temporaire à un membre de référence dans le ctor-initializer d'un constructeur (§12.6.2 [class.base.init]) persiste jusqu'à ce que le constructeur se termine.Réponses:
Seules les
const
références locales prolongent la durée de vie.La norme spécifie un tel comportement dans le §8.5.3 / 5, [dcl.init.ref], la section sur les initialiseurs de déclarations de référence. La référence dans votre exemple est liée à l'argument du constructeur
n
et devient invalide lorsque l'objetn
est lié à est hors de portée.L'extension de durée de vie n'est pas transitive via un argument de fonction. §12.2 / 5 [classe.temporaire]:
la source
member
c'est lié à un temporaire, car l'initialisationmember
avec desn
moyens de se liermember
au même objetn
est liée à, et c'est en fait un objet temporaire dans ce cas.const
quaifier.Voici le moyen le plus simple d'expliquer ce qui s'est passé:
Dans main (), vous avez créé une chaîne et l'avez passée au constructeur. Cette instance de chaîne n'existait que dans le constructeur. À l'intérieur du constructeur, vous avez affecté le membre pour qu'il pointe directement vers cette instance. Lorsque la portée a quitté le constructeur, l'instance de chaîne a été détruite et le membre a ensuite pointé vers un objet chaîne qui n'existait plus. Le fait que Sandbox.member pointe vers une référence en dehors de sa portée ne maintiendra pas ces instances externes dans la portée.
Si vous souhaitez corriger votre programme pour afficher le comportement souhaité, apportez les modifications suivantes:
Désormais, temp passera hors de portée à la fin de main () plutôt qu'à la fin du constructeur. Cependant, c'est une mauvaise pratique. Votre variable membre ne doit jamais être une référence à une variable qui existe en dehors de l'instance. En pratique, vous ne savez jamais quand cette variable sortira du champ d'application.
Ce que je recommande est de définir Sandbox.member comme un
const string member;
Cela copiera les données du paramètre temporaire dans la variable membre au lieu d'assigner la variable membre comme paramètre temporaire lui-même.la source
const string & temp = string("four"); Sandbox sandbox(temp); cout << sandbox.member << endl;
t-il toujours?const string &temp = string("four");
donne le même résultat queconst string temp("four");
, sauf si vous utilisezdecltype(temp)
spécifiquementHowever, this is bad practice.
- Pourquoi? Si la température et l'objet contenant utilisent le stockage automatique dans la même portée, n'est-il pas sûr à 100%? Et si vous ne le faites pas, que feriez-vous si la chaîne est trop grande et trop chère à copier?Techniquement parlant, ce programme n'est pas obligé de produire quoi que ce soit sur la sortie standard (qui est un flux tamponné pour commencer).
Le
cout << "The answer is: "
bit sera émis"The answer is: "
dans le tampon de stdout.Ensuite, le
<< sandbox.member
bit fournira la référence pendante dansoperator << (ostream &, const std::string &)
, qui invoque un comportement indéfini .Pour cette raison, rien n'est garanti. Le programme peut fonctionner en apparence correctement ou peut planter sans même vider stdout - ce qui signifie que le texte "La réponse est:" n'apparaîtra pas sur votre écran.
la source
"The answer is: "
cela sera écrit nulle part.Parce que votre chaîne temporaire est devenue hors de portée une fois le constructeur Sandbox retourné, et la pile occupée par elle a été récupérée à d'autres fins.
En règle générale, vous ne devez jamais conserver les références à long terme. Les références sont bonnes pour les arguments ou les variables locales, jamais pour les membres de la classe.
la source
vous parlez de quelque chose qui a disparu. Ce qui suit fonctionnera
la source