Pregunta

He encontrado un comportamiento extraño con una clase simple de 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; 
}

Esperaría violaciones de acceso o algo similar, pero nunca esperaría que el contenido de la cadena de constante estática pudiera cambiar. ¿Alguien aquí tiene una buena explicación de lo que sucede en ese código?

gracias, Norbert

¿Fue útil?

Solución

  

Esperaría violaciones de acceso o   algo similar, pero nunca esperaría   que el contenido de la constante estática   cadena podría cambiar.

Comportamiento indefinido: no está definido. Si CONST_STR ha sido destruido, no se le garantiza una excepción de hardware si accede a él. Podría bloquearse, pero de nuevo su dirección podría terminar conteniendo datos que parecen una cadena vacía: su destructor podría borrar punteros o lo que sea.

En este caso, usted dice que la instancia A también se almacena en un puntero inteligente global, que se asigna en main (). Por lo tanto, CONST_STR se ha construido cuando se accede a él en el constructor A, pero posiblemente se destruya antes de que se destruya el puntero inteligente. Necesitaríamos todo el programa para decirlo con seguridad.

[Editar: lo has hecho. Como CONST_STR y g_aStuff se definen en diferentes unidades de compilación, su orden relativo de construcción no está definido por el estándar. Supongo que CONST_STR se está destruyendo primero.]

Otros consejos

Editar: Aparentemente, el A :: que faltaba era un error tipográfico en la publicación original del código.

Respuesta original:

¿Quieres decir tener


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

para que el CONST_STR sea parte de la clase A ?

De lo contrario, lo declara por separado y no inicializa el miembro estático de A .

Estás creando 2 variables estáticas en dos unidades de compilación diferentes. No hay forma de saber en qué orden se inicializan. Pero sus destructores siempre se llaman en orden inverso.

En su caso, parece que se produjo el siguiente escenario:

g_aStuff constructor 
CONST_STR constructor

main funciton initializes g_aStuff

CONST_str destructor 
g_aStuff descrutor  

En este punto, el resultado de CONST_STR.empty () no está definido. Lo que puede desencadenar la afirmación.

El

const std::string CONST_STR("some text");
definido en classA.cpp no ??es miembro de A. Esa definición se vería así:

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

El estándar no especifica el orden de inicialización de objetos globales / estáticos en diferentes unidades de traducción. Sin embargo, garantiza que cada objeto se inicializará antes de que se ejecute cualquier función de esa unidad de traducción.

En su caso, sucede que CONST_STR se inicializa después de g_aStuff y, dado que el orden de destrucción es inverso al orden de construcción, se destruye antes. Por lo tanto, al acceder a CONST_STR desde el destructor de A se invoca un comportamiento indefinido: puede obtener una infracción de acceso o no.

Sin embargo,

CONST_STR se inicializa antes de que se ejecute el constructor de A porque están en la misma unidad de traducción.

Puede suceder si hay una instancia global de A (o un miembro de clase estática de tipo A). Dado que el orden de inicialización de globales y estáticos no está definido (unidades de traducción cruzada), puede serlo.

Mirando su código completo, confía en el orden de destrucción entre las unidades de compilación (classA.cpp y main.cpp). Si crea g_aStuff como local en main, sus afirmaciones deberían pasar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top