Domanda

Ho riscontrato un comportamento strano con una semplice 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; 
}

Mi aspetto violazioni dell'accesso o qualcosa di simile, ma non mi aspetto mai che il contenuto della stringa const statica possa cambiare. Qualcuno qui ha una buona spiegazione cosa succede in quel codice?

Grazie, Norbert

È stato utile?

Soluzione

  

Mi aspetto violazioni dell'accesso o   qualcosa di simile, ma non mi sarei mai aspettato   che il contenuto della const statica   la stringa potrebbe cambiare.

Comportamento indefinito: non definito. Se CONST_STR è stato distrutto, non ti viene garantita un'eccezione hardware se accedi. Potrebbe bloccarsi, ma poi il suo indirizzo potrebbe finire per contenere dati che sembrano una stringa vuota: il suo distruttore potrebbe cancellare i puntatori o altro.

In questo caso, dici che l'istanza A è anche memorizzata in un puntatore intelligente globale, che è assegnato in main (). Quindi CONST_STR è stato costruito quando vi si accede nel costruttore A, ma molto probabilmente viene distrutto prima che il puntatore intelligente venga distrutto. Avremmo bisogno di dire tutto il programma.

[Modifica: l'hai fatto. Poiché CONST_STR e g_aStuff sono definiti in diverse unità di compilazione, il loro ordine di costruzione relativo non è definito dallo standard. Immagino che CONST_STR sia stato distrutto per primo.]

Altri suggerimenti

Modifica: Apparentemente il A :: mancante era un refuso nel post originale del codice.

Risposta originale:

Intendi avere


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

in modo che CONST_STR faccia parte della classe A ?

Altrimenti lo stai dichiarando separatamente e non inizializzando il membro statico di A .

Stai creando 2 variabili statiche in due diverse unità di compilazione. Non c'è modo di dire in quale ordine sono inizializzati. Ma i loro distruttori sono sempre chiamati in ordine inverso.

Nel tuo caso sembra che si sia verificato il prossimo scenario:

g_aStuff constructor 
CONST_STR constructor

main funciton initializes g_aStuff

CONST_str destructor 
g_aStuff descrutor  

A questo punto il risultato di CONST_STR.empty () non è definito. Il che può innescare un'affermazione.

Il

const std::string CONST_STR("some text");
definito in classA.cpp non è un membro di A. Tale definizione sarebbe simile a:

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

Lo standard non specifica l'ordine di inizializzazione degli oggetti globali / statici in diverse unità di traduzione. Tuttavia, garantisce che ciascuno di tali oggetti verrà inizializzato prima che venga eseguita qualsiasi funzione da quell'unità di traduzione.

Nel tuo caso, accade che CONST_STR sia inizializzato dopo g_aStuff e, poiché l'ordine di distruzione è invertito rispetto all'ordine di costruzione, viene distrutto prima di esso. Pertanto, l'accesso a CONST_STR dal distruttore di A invoca comportamenti indefiniti: potresti avere una violazione di accesso oppure no.

CONST_STR viene, tuttavia, inizializzato prima che il costruttore di A sia eseguito perché si trovano nella stessa unità di traduzione.

Potrebbe accadere se esiste un'istanza globale di A (o un membro di classe statica di tipo A). Poiché l'ordine di inizializzazione di globali e statica non è definito (unità di traduzione incrociata), può esserlo.

Guardando il tuo codice completo, fai affidamento sull'ordine di distruzione tra le unità di compilazione (classA.cpp e main.cpp). Se crei g_aStuff come principale in locale, le tue affermazioni dovrebbero passare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top