Est-ce qu'un membre de la classe de référence const prolonger la durée de vie d'un temporaire?
-
03-10-2019 - |
Question
Pourquoi ceci:
#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 sortie:
La réponse est:
Au lieu de:
La réponse est: quatre
La solution
seulement références locales de const
prolonger la durée de vie.
La norme spécifie un tel comportement en §8.5.3 / 5, [dcl.init.ref], la section sur initializers des déclarations de référence. La référence dans votre exemple est lié à l'argument du constructeur de n
et devient invalide lorsque le n
d'objet est lié à est hors de portée.
L'extension de durée de vie est pas transitive par un argument de fonction. § 12.2 / 5 [class.temporary]:
Le second contexte est lorsqu'une référence est lié à un temporaire. Le temporaire dans lequel la référence est lié ou temporaire qui est l'objet complet à un sous-objet, dont le temporaire est persiste à destination de la durée de vie de la référence, sauf comme indiqué ci-dessous. Un temporaire lié à un élément de référence en cteur-initialiseur d'un constructeur (§12.6.2 [class.base.init]) persiste jusqu'à ce que les sorties du constructeur. Un temporaire lié à un paramètre de référence en un appel de fonction (§5.2.2 [expr.call]) persiste jusqu'à l'achèvement de la pleine expression contenant l'appel.
Autres conseils
Voici la façon la plus simple d'expliquer ce qui est arrivé:
Dans main () que vous avez créé une chaîne et passée dans le constructeur. Cette instance de chaîne n'existait dans le constructeur. A l'intérieur du constructeur, vous un membre assigné à pointer directement à cette instance. Lorsque la portée lorsque le constructeur a quitté, l'instance de chaîne a été détruite, et membre alors pointé un objet de chaîne qui n'existait plus. Ayant un point Sandbox.member à une référence en dehors de son champ d'application ne sera pas tenir ces instances externes portée.
Si vous voulez fixer votre programme pour afficher le comportement que vous désirez, apportez les modifications suivantes:
int main()
{
string temp = string("four");
Sandbox sandbox(temp);
cout << sandbox.member << endl;
return 0;
}
température passera hors de portée à la fin de main () au lieu de la fin du constructeur. Cependant, cela 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 sera hors de portée.
Ce que je recommande est de définir Sandbox.member comme const string member;
Cela copiera les données de paramètres temporaires dans la variable membre au lieu d'assigner la variable membre comme paramètre temporaire lui-même.
Sur le plan technique, ce programme n'a pas à quoi que ce soit réellement sortie standard (ce qui est un flux tampon pour commencer).
-
Le bit
cout << "The answer is: "
émettra"The answer is: "
dans la tampon de stdout. -
Le bit de
<< sandbox.member
fournira la référence boiteuse dansoperator << (ostream &, const std::string &)
, qui appelle comportement non défini .
En raison de cela, rien est garanti arriver. Le programme peut fonctionner en apparence bien ou peut se bloquer sans rinçage, même stdout - qui signifie que le texte « La réponse est: ». Ne s'apparaître sur votre écran
Parce que votre chaîne temporaire est sorti de champ une fois que le constructeur Bac à sable retourné, et la pile occupée par elle a été récupérée pour d'autres fins.
En général, vous ne devriez jamais retenir les références à long terme. Les références sont bonnes pour les arguments ou les variables locales, jamais les membres de la classe.
vous faites référence à quelque chose qui a disparu. Ce qui suit fonctionne
#include <string>
#include <iostream>
class Sandbox
{
public:
const string member = " "; //default to whatever is the requirement
Sandbox(const string& n) : member(n) {}//a copy is made
};
int main()
{
Sandbox sandbox(string("four"));
std::cout << "The answer is: " << sandbox.member << std::endl;
return 0;
}