43 votes

Pourquoi cela fonctionne-t-il : retour d'un littéral de chaîne C à partir de la fonction std::string et appel de c_str()

Lors d'un récent cours à l'université, notre professeur nous a expliqué les différentes choses auxquelles il faut faire attention lorsqu'on programme dans différents langages. Voici un exemple en C++ :

std::string myFunction()
{
    return "it's me!!";
}

int main(int argc, const char * argv[])
{
    const char* tempString = myFunction().c_str();

    char myNewString[100] = "Who is it?? - ";
    strcat(myNewString, tempString);
    printf("The string: %s", myNewString);

    return 0;
}

L'idée de l'échec est la suivante return "it's me!!" appelle implicitement le constructeur std::string avec un char[]. Cette chaîne est renvoyée par la fonction et la fonction c_str() renvoie un pointeur sur les données de la std::string .

Comme la chaîne renvoyée par la fonction n'est référencée nulle part, elle doit être désallouée immédiatement. Telle était la théorie.

Cependant, l'exécution de ce code fonctionne sans problème. Je serais curieux de savoir ce que vous en pensez. Merci de votre compréhension.

23 votes

Il ne fonctionne pas "sans problème", il ne fait que fait semblant de travailler. Il s'agit d'un comportement non défini, donc tout peut arriver.

4 votes

La mémoire est allouée différemment, mais cette réponse reste valable : stackoverflow.com/a/6445794/13005

0 votes

@SteveJessop +1, je cherchais justement le même lien pour le poster ici.

45voto

juanchopanza Points 115680

Votre analyse est correcte. Ce que vous avez est comportement non défini . Cela signifie que tout peut arriver. Dans votre cas, il semble que la mémoire utilisée pour la chaîne de caractères, bien que désallouée, contienne toujours le contenu original lorsque vous y accédez. Cela se produit souvent parce que le système d'exploitation n'efface pas la mémoire désallouée. Il se contente de la marquer comme disponible pour une utilisation future. Le langage C++ n'a pas à s'en préoccuper : il s'agit en fait d'un détail d'implémentation du système d'exploitation. En ce qui concerne le langage C++, c'est l'expression fourre-tout "comportement non défini" qui s'applique.

1 votes

Notez que dans ce cas, le contenu de la chaîne est probablement sur la pile, parce qu'elle est courte. Vous ne devriez donc pas obtenir de défaut de ségrégation, tout au plus un déchet.

12 votes

This often happens because the OS does not clear out de-allocated memory. pas vrai. Ce n'est pas le système d'exploitation qui est en cause, mais l'implémentation de malloc, qui peut être tierce comme jemalloc ou même personnalisée.

5voto

jbgs Points 868

Je suppose que la désallocation n'implique pas le nettoyage de la mémoire ou la mise à zéro. Et il est évident que cela pourrait conduire à un défaut de segmentation dans d'autres circonstances.

3voto

StackedCrooked Points 12247

Comme d'autres l'ont mentionné, selon la norme C++, il s'agit d'un comportement non défini.

La raison pour laquelle cela "fonctionne" est que la mémoire a été rendue au gestionnaire de tas qui la conserve en vue d'une réutilisation ultérieure. La mémoire a no a été rendu à l'OS et appartient donc toujours au processus. C'est pourquoi l'accès à la mémoire libérée ne provoque pas d'erreur de segmentation. Le problème reste cependant que maintenant deux parties de votre programme (votre code et le gestionnaire de tas ou le nouveau propriétaire) accèdent à la mémoire qu'ils pensent leur appartenir de manière unique. Cela détruira les choses tôt ou tard.

1voto

marcolz Points 39

Le fait que la chaîne soit désallouée ne signifie pas nécessairement que la mémoire n'est plus accessible. Tant que vous ne faites rien qui puisse l'écraser, la mémoire est toujours utilisable.

0 votes

Le destructeur de la chaîne de caractères libère son pointeur et tempString pointe toujours vers lui ; le déréférencement de tempString conduit à UB.

0 votes

Tant que vous... et le destructeur de std::string, le gestionnaire de tas, le gestionnaire de mémoire du système d'exploitation ou un autre thread ne font rien...

1voto

VitaliG Points 11

Comme indiqué plus haut, il s'agit d'un comportement imprévisible. Cela ne fonctionne pas pour moi (en configuration Debug). Le destructeur std::string est appelé immédiatement après l'affectation à la chaîne temporaire - lorsque l'expression utilisant l'objet chaîne temporaire se termine. La chaîne tempString pointe donc sur une mémoire libérée (qui, dans votre cas, contient toujours les lettres "c'est moi !!").

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X