web-dev-qa-db-fra.com

Résultat inattendu lorsque l'élément de stockage C ++ dans std :: vector à partir de la valeur de retour de la fonction

Lorsque la fonction implique une réallocation, j'ai trouvé que certains compilateurs peuvent enregistrer l'adresse avant l'appel de la fonction. Il entraîne la valeur de retour stockée dans l'adresse non valide.

Il y a un exemple pour expliquer le comportement dans la description ci-dessus.

#include <stdio.h>
#include <vector> 
using namespace std;

vector<int> A; 
int func() { 
    A.Push_back(3);
    A.Push_back(4);
    return 5; 
} 
int main() { 
    A.reserve(2);
    A.Push_back(0);
    A.Push_back(1);
    A[1] = func();
    printf("%d\n", A[1]);
    return 0;
}

Il existe des compilateurs C++ courants et le résultat du test est le suivant.

  • GCC (GNU Compiler Collection): Erreur d'exécution ou sortie 1
  • Clang: sortie 5
  • VC++: sortie 5

S'agit-il d'un comportement indéfini?

45
Morris Yang

Le comportement n'est pas défini dans toutes les versions C++ antérieures à C++ 17. La raison simple est que les deux côtés de l'opérateur d'affectation peuvent être évalués dans n'importe quel ordre:

  • En supposant que A[1] Est évalué en premier, vous obtenez un int& Faisant référence au deuxième élément de A à ce stade.
  • Ensuite, la func() est évaluée, ce qui peut réallouer le stockage pour le vecteur, laissant au int& Précédemment récupéré une référence pendante.
  • Enfin, l'affectation est effectuée, en écrivant sur le stockage non alloué. Étant donné que la mémoire cache des allocateurs standard, le système d'exploitation ne détecte souvent pas cette erreur.

Uniquement en C++ 17, la règle spéciale 2 pour l'affectation a été faite:

Dans chaque expression d'affectation simple E1 = E2 et dans chaque expression d'affectation composée E1 @ = E2, chaque calcul de valeur et effet secondaire d'E2 est séquencé avant chaque calcul de valeur et effet secondaire d'E1

Avec C++ 17, A[1] Doit être évalué après l'appel à func(), qui fournit alors un comportement défini et fiable.

51
Ulrich Eckhardt