Может ли статическая выделенная память стать недействительной во время статической деинициализации? - PullRequest
2 голосов
/ 24 сентября 2010

Скажите, что я определил переменную, подобную этой (C ++):

static const char str[] = "Here is some string data";

И у меня есть статически размещенный экземпляр класса, который ссылается на этот массив в его деструкторе, может ли это пойти не так? Например. может ли переменная str как-то стать недействительной?

class A {
 ~A() {
   cout << str << endl;
 }
};

static A a;

Я предполагаю, что это не может пойти не так, но я могу найти это четко изложенным где угодно. Я хочу знать это наверняка. Я предполагаю, что мы не можем предсказать последовательность вызова деструкторов для статически размещенных объектов, но сами данные никогда не освобождаются до тех пор, пока процесс не будет сорван. Значения указателей на POD должны быть безопасными, но не экземпляры объектов.

Значение, например, это:

static const QString str = "Here is some string data";

или

static const std::string str = "Here is some string data";

Нельзя безопасно использовать в деструкторе A , поскольку они оба распределяют свои строковые данные в куче, и это может быть освобождено деструктором до вызова деструктора A .

Верно ли мое предположение, и есть ли в стандарте C ++ какие-либо разделы, объясняющие эту или какую-либо ссылку на какой-либо другой орган, который может это проверить?

Ответы [ 3 ]

2 голосов
/ 29 сентября 2010

Хорошо, я попытался самостоятельно прочитать стандарт C ++, чтобы найти ответы на некоторые вопросы. Из полученных ответов я вижу, что существует большая путаница в разнице между созданием объекта и его распределением.

Из стандарта:

3.6.2 Инициализация нелокальных объектов

Объекты со статической продолжительностью хранения (3.7.1) инициализируется нулями (8.5) перед любой другой инициализацией происходит. Ссылка со статическим срок хранения и объект POD тип со статической длительностью хранения может быть инициализирован с константой выражение (5.19); это называется постоянная инициализация. Все вместе, нулевая инициализация и постоянная инициализация называется статической инициализация; все остальные инициализация динамическая инициализация. Статическая инициализация должно быть выполнено до любого динамического инициализация происходит. динамический инициализация объекта либо заказанный или неупорядоченный.

Моя интерпретация этого заключается в том, что const char [] всегда будет гарантированно установлен до запуска любого конструктора.

3.6.3 Прекращение Деструкторы (12.4) для инициализированных объектов со статической продолжительностью хранения (объявленные в области блока или в области пространства имен) вызывается в результате возврата из main и в результате вызова std :: exit (18.3). Эти объекты уничтожены в обратный порядок завершения их конструктора или завершения их динамической инициализации. Если объект при статической инициализации объект уничтожается в том же порядке, как если бы объект был динамически инициализирован.

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

Что должно объяснить, почему в стандарте Google C ++ написано, что вы должны использовать только POD-типы с константными выражениями. :

В результате мы разрешаем только статическим переменным содержать данные POD. Это правило полностью запрещает vector (используйте вместо этого массивы C) или строку (используйте const char []).

2 голосов
/ 24 сентября 2010

Порядок, в котором вызываются деструкторы для автоматических, глобальных и статических объектов, всегда хорошо определен: это обратный порядок, в котором вызываются конструкторы.Поэтому, если объект A ссылается на объект B, а B был созданный до A, вы можете быть уверены, что B это , уничтоженный после A.Это оставляет нас с вопросом о порядке конструкторов.

Вот что я помню:

  1. Глобальные и статические объекты создаются до вызова main().
  2. Классы локального класса создаются перед любым объектом их класса.
  3. Функционально-локальные статики создаются при первом достижении их объема.
  4. Глобальные и статические объекты в пределах одной и той же единицы перевода создаются в порядке, в котором они определены.(Это означает, что порядок включения заголовков может повлиять на это!)
  5. Порядок построения глобальных и статических объектов в единицах перевода не определен.

Я немного запутался в некоторых из них, поэтому, пожалуйста, поправьте меня, если считаете, что это неправильно.

0 голосов
/ 24 сентября 2010

Если я правильно помню, глобальная инициализация объекта не определена в стандарте (или плохо определена), что затрудняет глобальные объекты для ссылки друг на друга.

Если вы хотите быть уверены в порядке инициализации, используйте глобальную функцию с вашим статическим объектом, которая просто возвращает его.Теперь вы гарантированы, что статический объект будет инициализирован при первом вызове функции.

Уничтожение произойдет в конце приложения после выхода из main ().

...