Le C ++ fournit-il une garantie pour la durée de vie d'une variable temporaire créée dans un appel de fonction mais non utilisée comme paramètre? Voici un exemple de classe:
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
Et voici comment vous l'utiliseriez:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
Quand le destructeur de l'objet StringBuffer temporaire sera-t-il appelé? Est-ce:
- Avant l'appel à GetString?
- Après le retour de GetString?
- Dépendant du compilateur?
Je sais que C ++ garantit qu'une variable temporaire locale sera valide tant qu'il y aura une référence à elle - cela s'applique-t-il aux objets parents lorsqu'il y a une référence à une variable membre?
Merci.
m_str.reserve(maxlength)
àchar * Size(int maxlength)
, sinon le destructeur pourrait jeter.Réponses:
Le destructeur pour ce type de temporaires est appelé à la fin de l'expression complète. C'est l'expression la plus externe qui ne fait partie d'aucune autre expression. C'est dans votre cas après le retour de la fonction et l'évaluation de la valeur. Donc, tout fonctionnera bien.
C'est en fait ce qui fait fonctionner les modèles d'expression: ils peuvent conserver des références de conservation à ce type de temporels dans une expression comme
Parce que chaque temporaire durera jusqu'à l'expression
Est évalué complètement. Il est décrit de manière assez concise
12.2 Temporary objects
dans la norme.la source
printf("%s", strdup(std::string("$$$").c_str()) );
Je veux dire sistrdup(std::string("$$$").c_str())
est considérée comme l'expression complète, alors le pointeur quistrdup
voit est valide . Sistd::string("$$$").c_str()
est une expression complète, alors le pointeur quistrdup
voit n'est pas valide ! Pourriez-vous s'il vous plaît expliquer un peu plus en vous basant sur cet exemple?printf
est l'expression complète. Ilstrdup
s'agit donc d'une fuite de mémoire inutile - vous pouvez simplement le laisser imprimerc_str()
directement.La réponse de litb est exacte. La durée de vie de l'objet temporaire (également appelée rvalue) est liée à l'expression et le destructeur de l'objet temporaire est appelé à la fin de l'expression complète et lorsque le destructeur sur StringBuffer est appelé, le destructeur sur m_buffer sera également appelé, mais pas le destructeur sur m_str puisqu'il s'agit d'une référence.
Notez que C ++ 0x change un peu les choses car il ajoute des références rvalue et déplace la sémantique. Essentiellement en utilisant un paramètre de référence rvalue (noté avec &&), je peux `` déplacer '' la rvalue dans la fonction (au lieu de la copier) et la durée de vie de la rvalue peut être liée à l'objet dans lequel elle se déplace, pas à l'expression. Il y a un très bon article de blog de l'équipe MSVC sur ce sujet en détail et j'encourage les gens à le lire.
L'exemple pédagogique pour déplacer les rvalue est des chaînes temporaires et je vais montrer l'affectation dans un constructeur. Si j'ai une classe MyType qui contient une variable membre de chaîne, elle peut être initialisée avec une rvalue dans le constructeur comme ceci:
C'est bien car lorsque je déclare une instance de cette classe avec un objet temporaire:
ce qui se passe, c'est que nous évitons de copier et de détruire l'objet temporaire et "hello" est placé directement dans la variable membre de l'instance de classe propriétaire. Si l'objet est plus lourd qu'une «chaîne», l'appel de copie et de destructeur supplémentaire peut être significatif.
la source
Après le retour de l'appel à GetString.
la source
StringBuffer est dans la portée de GetString. Il devrait être détruit à la fin de la portée de GetString (c'est-à-dire quand il revient). De plus, je ne crois pas que C ++ garantira qu'une variable existera tant qu'il y aura référence.
Les éléments suivants doivent être compilés:
la source
J'ai écrit presque exactement la même classe:
Avant le standard, chaque compilateur le faisait différemment. Je crois que l'ancien manuel de référence annoté pour C ++ spécifiait que les temporaires devraient nettoyer à la fin de la portée, c'est pourquoi certains compilateurs l'ont fait. En 2003, j'ai trouvé que le comportement existait toujours par défaut sur le compilateur Forte C ++ de Sun, donc StringBuffer ne fonctionnait pas. Mais je serais étonné si un compilateur actuel était toujours aussi cassé.
la source