C ++ статическая постоянная переменная и уничтожение
-
06-07-2019 - |
Вопрос
Я столкнулся со странным поведением простого класса C ++.
Класс a.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 может измениться.У кого-нибудь здесь есть хорошее объяснение, что происходит в этом коде?
спасибо, Норберт
Решение
Я бы ожидал нарушений доступа или чего-нибудь подобного, но я бы никогда не ожидал что содержимое static const строка может измениться.
Неопределенное поведение:это не определено.Если CONST_STR был уничтожен, то вам не гарантируется аппаратное исключение при обращении к нему.Это может привести к сбою, но опять же, его адрес может в конечном итоге содержать данные, которые выглядят как пустая строка:его деструктор может очищать указатели или что-то в этом роде.
В этом случае вы говорите, что экземпляр A также хранится в глобальном интеллектуальном указателе, который присваивается в main().Таким образом, CONST_STR был создан при обращении к нему в конструкторе A, но, вполне возможно, уничтожен до уничтожения интеллектуального указателя.Нам нужна была бы вся программа, чтобы сказать наверняка.
[Править:ты сделал это.Поскольку CONST_STR и g_aStuff определены в разных единицах компиляции, их относительный порядок построения стандартом не определен.Я предполагаю, что CONST_STR уничтожается первым.]
Другие советы
Редактировать: По - видимому , пропавший A::
была опечатка в исходном сообщении кода.
Оригинальный Ответ:
Вы имеете в виду иметь
const std::string A::CONST_STR("some text");
так что CONST_STR является частью класса A
?
В противном случае вы объявляете его отдельно и не инициализация статического члена A
.
Вы создаете 2 статические переменные в двух разных единицах компиляции.Нет никакого способа определить, в каком порядке они инициализируются.Но их деструкторы всегда вызываются в обратном порядке.
В вашем случае, похоже, имел место следующий сценарий:
g_aStuff constructor
CONST_STR constructor
main funciton initializes g_aStuff
CONST_str destructor
g_aStuff descrutor
На данный момент результат CONST_STR.empty() не определен.Что может вызвать assert .
В
const std::string CONST_STR("some text");
определено в classA.cpp не является членом A.Это определение выглядело бы следующим образом:
const std::string A::CONST_STR("some text");
Стандарт не определяет порядок инициализации глобальных / статических объектов в разных единицах перевода.Однако это гарантирует, что каждый такой объект будет инициализирован до выполнения какой-либо функции из этой единицы преобразования.
В вашем случае случается так, что CONST_STR
инициализируется после g_aStuff
и, поскольку порядок разрушения обратный порядку построения, он уничтожается раньше.Таким образом, доступ к CONST_STR
От A
деструктор вызывает неопределенное поведение - вы можете получить нарушение доступа, а можете и нет.
CONST_STR
однако инициализируется перед A
конструктор выполняется, потому что они находятся в одной и той же единице перевода.
Это может произойти, если существует глобальный экземпляр A (или статический член класса типа A).Поскольку порядок инициализации глобальных значений и статики не определен (единицы перекрестного перевода), это может быть.
Глядя на ваш полный код, вы полагаетесь на порядок уничтожения в единицах компиляции (classA.cpp и main.cpp).Если вы создадите g_aStuff как локальный в main, ваши утверждения должны пройти.