Question

J'ai rencontré un comportement étrange avec une simple classe C ++.

classA.h

class A
{
public:
  A();
  ~A();
  static const std::string CONST_STR;
};

classA.cpp

#include "classA.h"
#include <cassert>

const std::string A::CONST_STR("some text");

A::A()
{
  assert(!CONST_STR.empty()); //OK
}

A::~A()
{
  assert(!CONST_STR.empty()); //fails
}

main.cpp

#include <memory>  
#include <classA.h>  

std::auto_ptr<A> g_aStuff; 

int main() 
{ 
  //do something ... 
  g_aStuff = std::auto_ptr<A>(new A()); 
  //do something ... 
  return 0; 
}

Je m'attendrais à des violations d'accès ou à quelque chose de similaire, mais je ne m'attendrais jamais à ce que le contenu de la chaîne de const statique puisse changer. Quelqu'un at-il ici une bonne explication de ce qui se passe dans ce code?

merci, Norbert

Était-ce utile?

La solution

  

Je m'attendrais à des violations d'accès ou   quelque chose de similaire, mais je ne m'attendrais jamais   que le contenu de la constante statique   la chaîne pourrait changer.

Comportement indéfini: il est indéfini. Si CONST_STR a été détruit, une exception matérielle ne vous est pas garantie si vous y accédez. Il se peut qu’il plante, mais son adresse peut finir par contenir des données qui ressemblent à une chaîne vide: son destructeur peut effacer les pointeurs ou autre chose.

Dans ce cas, vous dites que l'instance A est également stockée dans un pointeur intelligent global, qui est attribué dans main (). Ainsi, CONST_STR a été construit lors de son accès dans le constructeur A, mais est probablement détruit avant le pointeur intelligent. Nous aurions besoin de tout le programme pour le dire avec certitude.

[Edit: vous l'avez fait. Puisque CONST_STR et g_aStuff sont définis dans différentes unités de compilation, leur ordre de construction relatif n’est pas défini par la norme. Je suppose que CONST_STR est détruit en premier.]

Autres conseils

Modifier: Apparemment, le A :: manquant était une faute de frappe dans le message d'origine du code.

Réponse originale:

Voulez-vous dire


    const std::string A::CONST_STR("some text");

afin que CONST_STR fasse partie de la classe A ?

Sinon, vous le déclarez séparément et pas l'initialisation du membre statique de A .

Vous créez 2 variables statiques dans deux unités de compilation différentes. Il n'y a aucun moyen de savoir dans quel ordre ils sont initialisés. Mais leurs destructeurs sont toujours appelés dans l’ordre inverse.

Dans votre cas, il semble que le scénario suivant ait eu lieu:

g_aStuff constructor 
CONST_STR constructor

main funciton initializes g_aStuff

CONST_str destructor 
g_aStuff descrutor  

À ce stade, le résultat de CONST_STR.empty () n’est pas défini. Ce qui peut déclencher une affirmation.

Le

const std::string CONST_STR("some text");
défini dans classA.cpp n'est pas membre de A. Cette définition ressemblerait à ceci:

const std::string A::CONST_STR("some text");

La norme ne spécifie pas l'ordre d'initialisation des objets globaux / statiques dans différentes unités de traduction. Toutefois, il garantit que chaque objet de ce type sera initialisé avant l'exécution d'une fonction quelconque de cette unité de traduction.

Dans votre cas, il arrive que CONST_STR soit initialisé après g_aStuff et, l'ordre de destruction étant inversé par rapport à l'ordre de construction, il est détruit avant. Ainsi, l'accès à CONST_STR à partir de le destructeur de appelle un comportement indéfini - vous pouvez obtenir une violation d'accès ou vous ne pouvez pas.

CONST_STR est cependant initialisé avant le constructeur de Un constructeur est exécuté car ils se trouvent dans la même unité de traduction.

Cela peut arriver s'il existe une instance globale de A (ou un membre de classe statique de type A). Dans la mesure où l'ordre d'initialisation des globaux et de la statique n'est pas défini (unités de traduction croisée), il peut l'être.

En regardant votre code complet, vous vous fiez à l'ordre de destruction entre les unités de compilation (classA.cpp et main.cpp). Si vous créez g_aStuff en tant que local dans main, vos assertions doivent être acceptées.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top