Инициализация глобального объекта POD - PullRequest
3 голосов
/ 02 июня 2010

Сегодня меня укусила ошибка.

Вопрос для юристов C ++

Рассмотрим следующий источник:

struct MyPod
{
   short              m_short ;
   const char * const m_string ;
} ;

MyPod myArrayOfPod[] = { { 1, "Hello" } } ;

int main(int argc, char * argv[])
{
   return 0 ;
}

Обратите внимание, что все значения известны во время компиляции, и что MyPod является POD.

Итак, должен ли myArrayOfPod быть инициализирован во время компиляции, или компилятор сгенерирует какой-то конструктор MyPod по умолчанию?

Подробности, включая автономный источник

Следующий источник, который воспроизводит ошибку, можно скопировать / вставить в файл main.cpp:

#include <iostream>

// The point of SomeGlobalObject is for its
// constructor to be launched before the main
// ...
struct SomeGlobalObject
{
   SomeGlobalObject() ;
} ;

// ...
// Which explains the global object
SomeGlobalObject oSomeGlobalObject ;

// A POD... I was hoping it would be constructed at
// compile time when using an argument list
struct MyPod
{
   short              m_short ;
   const char * const m_string ;
} ;

// declaration/Initialization of a MyPod array
MyPod myArrayOfPod[] = 
{ { 1, "Hello" }, { 2, "World" }, { 3, " !" } } ;

// declaration/Initialization of an array of array of void *
void * myArrayOfVoid[][2] = 
{ { (void *)1, "Hello" }, { (void *)2, "World" }, { (void *)3, " !" } } ;

// constructor of the global object... Launched BEFORE main
SomeGlobalObject::SomeGlobalObject()
{
   // The two values should be "1"
   std::cout << "myArrayOfPod[0].m_short : " << myArrayOfPod[0].m_short << std::endl ;
   std::cout << "myArrayOfVoid[0][0] : " << myArrayOfVoid[0][0] << std::endl ;
}

// main... What else ?
int main(int argc, char* argv[])
{
   return 0 ;
}

MyPod, будучи POD, я верил, что конструкторов не будет. Только инициализация во время компиляции.

Таким образом, глобальный объект SomeGlobalObject не будет иметь проблем с использованием глобального массива POD при его создании.

Но в Visual C ++ 2008 в режиме отладки при выполнении myArrayOfPod не инициализируется должным образом (все его значения обнуляются), даже если myArrayOfVoid правильно инициализирован.

Итак, мои вопросы: Разве компиляторы C ++ не должны инициализировать глобальные POD (включая структуры POD) во время компиляции?

Displaimer

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

Редактировать

Я скопировал / вставил этот код в свою Ubuntu, и, что касается g ++ 4.4.3, эти два массива правильно инициализированы как в режиме отладки, так и в режиме выпуска.

О поведении сообщили в Microsoft и ожидают подтверждения: https://connect.microsoft.com/VisualStudio/feedback/details/564844/pod-struct-global-object-initialization-uses-constructor

Редактировать 2

Visual C ++ QA ответил на сообщение об ошибке, цитируя стандарт (по крайней мере, n3092 ). Что касается их поведения, то поведение, наблюдаемое в Visual C ++, соответствует стандарту.

И несмотря на мои "чувства", это все еще ошибка, я должен признать тот факт, что они знают стандарт бесконечно больше, чем я (хотя бы потому, что я использую язык , когда они пишут компилятор для языка ), и, таким образом, принять свой ответ.

Итак, я сделаю домашнее задание, то есть прочитаю n3092 от начала до конца (Тысяча страниц подобных юристам заявлений ... Это моя удача ...) : В этом документе используется много четко определенных слов, и если я не знаю точного значения каждого слова, я не смогу процитировать какой-то параграф n3092 , чтобы поддержать мою точку зрения ...

Благодарю MSN и AndreyT за ответы.

Ответы [ 4 ]

3 голосов
/ 02 июня 2010

Согласно стандарту C ++, 3.6.2.2: Инициализация нелокальных объектов:

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

Поскольку myArrayOfPod хотя бы на первый взгляд инициализируется постоянным выражением, его следует инициализировать до oSomeGlobalObject. Тот факт, что он не находится в режиме отладки, вероятно, является ошибкой. Вы можете отправить сообщение об ошибке через connect.microsoft.com .

1 голос
/ 02 июня 2010

Язык C ++ гарантирует, что POD-объекты со статической продолжительностью хранения, инициализированные константными выражениями , инициализируются статически , т.е. Более педантично, независимо от того, как реализована статическая инициализация (во время компиляции, во время выполнения), она должна происходить за до любой динамической инициализации. Например, вызов конструктора - это динамическая инициализация.

В вашем случае myArrayOfPod - это POD, целочисленные литералы - это целочисленные константные выражения, а строковые литералы - это адресные константные выражения. Я бы сказал, что ваш myArrayOfPod удовлетворяет всем требованиям и поэтому должен быть статически инициализирован. Если вы наблюдаете неинициализированный myArrayOfPod из конструктора oSomeGlobalObject в вашем эксперименте, это должно быть ошибкой в ​​компиляторе.

0 голосов
/ 02 июня 2010

Разве компиляторы C ++ не должны инициализировать глобальные POD (включая структуры POD) во время компиляции?

Нет. Как бы они? Это конструкции времени выполнения. Даже если компилятор встроил все в описание программы (постоянные значения в стеке), он все равно должен быть инициализирован во время выполнения.

IRC, в пределах одной и той же единицы перевода порядок инициализации глобалов гарантированно будет в порядке объявления. Подумайте, где находится ваш глобальный объект внутри файла.

Если я ошибаюсь, порядок не определен. Кроме того, когда мы говорим о глобальных единицах в единицах перевода, порядок не определен. В этом я уверен.

0 голосов
/ 02 июня 2010

Мне кажется, это точка, в которой порядок инициализируются глобалы, а не ли они.Должно быть, режим отладки вызывает глобальный код инициализации в другом порядке, нежели режим выпуска.

Глобальные ссылки, ссылающиеся на глобальные ... возможны ли степени зла?; -)

Редактировать: Предположительно, если вы поместите два cout в главный, вы увидите, что все глобальные переменные были инициализированы к тому времени, как он туда доберется.

...