C ++ статическая переменная const и уничтожение - PullRequest
1 голос
/ 19 июня 2009

Я столкнулся со странным поведением с простым классом 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; 
}

Я бы ожидал нарушения прав доступа или чего-то подобного, но я бы никогда не ожидал, что содержимое статической строки const может измениться. У кого-нибудь здесь есть хорошее объяснение того, что происходит в этом коде?

спасибо, Норберт

Ответы [ 7 ]

3 голосов
/ 19 июня 2009

Редактировать: Видимо, пропущенный A:: был опечаткой в ​​исходном посте кода.

Оригинальный ответ:

Вы хотите иметь


    const std::string <b>A::</b>CONST_STR("some text");

так что CONST_STR является частью класса A?

В противном случае вы объявляете его отдельно, а не инициализируете статический член A.

2 голосов
/ 19 июня 2009

Я ожидаю нарушения доступа или ничего подобного, но я бы никогда не ожидал что содержание статического конста строка может измениться.

Неопределенное поведение: оно не определено. Если CONST_STR был уничтожен, то вам не гарантировано аппаратное исключение, если вы получите к нему доступ. Может произойти сбой, но с другой стороны, его адрес может содержать данные, которые выглядят как пустая строка: его деструктор может очистить указатели или что-то еще.

В этом случае вы говорите, что экземпляр A также хранится в глобальном интеллектуальном указателе, который назначается в main (). Таким образом, CONST_STR был создан при обращении к нему в конструкторе A, но вполне возможно, что он уничтожен до уничтожения умного указателя. Нам нужна вся программа, чтобы сказать наверняка.

[Редактировать: вы сделали это. Поскольку CONST_STR и g_aStuff определены в разных единицах компиляции, их относительный порядок построения не определен стандартом. Я предполагаю, что CONST_STR уничтожается первым.]

2 голосов
/ 19 июня 2009

Вы создаете 2 статические переменные в двух разных единицах компиляции. Невозможно определить, в каком порядке они инициализируются. Но их деструкторы всегда вызываются в обратном порядке.

В вашем случае кажется, что произошел следующий сценарий:

g_aStuff constructor 
CONST_STR constructor

main funciton initializes g_aStuff

CONST_str destructor 
g_aStuff descrutor  

На данный момент результат CONST_STR.empty () не определен. Который может вызвать утверждение.

1 голос
/ 19 июня 2009

Стандарт не определяет порядок инициализации глобальных / статических объектов в разных единицах перевода. Это, однако, гарантирует, что каждый такой объект будет инициализирован перед выполнением любой функции из этого модуля перевода.

В вашем случае, случается, что CONST_STR инициализируется после g_aStuff и, поскольку порядок уничтожения является обратным порядку построения, он уничтожается до этого. Таким образом, доступ к деструктору CONST_STR из A вызывает неопределенное поведение - вы можете получить нарушение прав доступа или нет.

Однако

CONST_STR инициализируется до выполнения конструктора A, поскольку они находятся в одной и той же единице перевода.

1 голос
/ 19 июня 2009

const std::string CONST_STR("some text");
, определенный в classA.cpp, не является членом A. Это определение будет выглядеть так:
const std::string A::CONST_STR("some text");
0 голосов
/ 19 июня 2009

Глядя на свой полный код, вы полагаетесь на порядок уничтожения в единицах компиляции (classA.cpp и main.cpp). Если вы создадите g_aStuff как локальный в main, ваши утверждения должны пройти.

0 голосов
/ 19 июня 2009

Это может произойти, если существует глобальный экземпляр A (или член статического класса типа A). Поскольку порядок инициализации глобалов и статики не определен (единицы кросс-перевода), он может быть.

...