Pergunta

Eu encontrei um comportamento estranho com uma simples 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; 
}

Eu esperaria violações de acesso ou qualquer coisa semelhante, mas eu nunca esperaria que o conteúdo da string const estática pode mudar. Alguém aqui tem uma boa explicação que acontece nesse código?

graças, Norbert

Foi útil?

Solução

Eu esperaria violações de acesso ou algo semelhante, mas eu nunca esperaria que o conteúdo da const estática corda pode mudar.

comportamento indefinido: ela é indefinida. Se CONST_STR foi destruído, então você não está garantida uma exceção de hardware se você acessá-lo. Ele pode falhar, mas, novamente seu endereço pode acabar contendo dados que se parece com uma cadeia vazia:. Respectivo processo de destruição pode limpar ponteiros ou o que quer

Neste caso, você diz que a instância A também é armazenado em um ponteiro inteligente global, que é atribuído em main (). Assim, o CONST_STR foi construído quando ele é acessado no construtor A, mas muito possivelmente é destruído antes que o ponteiro inteligente é destruído. Precisaríamos todo o programa para dizer com certeza.

[Edit: você já fez isso. Desde CONST_STR e g_aStuff são definidos em diferentes unidades de compilação, sua ordem relativa de construção não é definido pela norma. Eu estou supondo que CONST_STR está sendo destruído em primeiro lugar.]

Outras dicas

Editar: Aparentemente, o A:: faltando era um erro de digitação no post original do código.

Resposta Original:

Você quer dizer ter


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

para que o CONST_STR faz parte de A classe?

Caso contrário, você está declarando-lo separadamente e não inicializar o membro estático de A.

Você está criando 2 variáveis ??estáticas em duas unidades de compilação diferentes. Não há nenhuma maneira de saber em que ordem eles são inicializados. Mas seus destruidores são sempre chamados em ordem inversa.

No seu caso parece que próximo cenário ocorreu:

g_aStuff constructor 
CONST_STR constructor

main funciton initializes g_aStuff

CONST_str destructor 
g_aStuff descrutor  

Neste resultado ponto de CONST_STR.empty () é indefinido. O que pode desencadear assert.

O

const std::string CONST_STR("some text");
definido no classA.cpp não é membro de A. Essa definição seria algo como:

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

A norma não especifica a ordem de inicialização de objetos globais / estáticos em diferentes unidades de tradução. É, no entanto, garantia de que cada tal objeto será inicializado antes de qualquer função daquela unidade de tradução é executada.

No seu caso, acontece que CONST_STR é inicializado após g_aStuff e, uma vez que a ordem de destruição é inversa da ordem de construção, ele é destruído antes dele. Assim, o acesso a CONST_STR de invoca destruidor de A comportamento indefinido -. Você pode obter uma violação de acesso ou você não pode

CONST_STR é, no entanto, inicializado antes construtor de A é executado porque eles estão na mesma unidade de tradução.

Pode acontecer se houver uma instância global de A (ou um membro da classe estática do tipo A). Desde o fim da inicialização de globals e estática não está definido (unidades de tradução de cruz), ele pode ser.

Olhando para o seu código completo, você está contando com a ordem de destruição em todas as unidades de compilação (classA.cpp e main.cpp). Se você criar g_aStuff como um local na principal, o afirma deve passar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top