2009-07-10 5 views
3

В одном и том же модуле компиляции стандарт C++ говорит, что статический порядок инициализации хорошо определен - это порядок объявлений статических объектов. Но используя компилятор Sun Studio 12, я сталкиваюсь с неинтуитивным поведением. Я определил шаблонный класс helper<T>, который содержит статический член _data типа T и статическую функцию-член, которая использует _data по номеру foo. В моем файле .cpp я это выше основного():Выполняет ли typedefs шаблонов статический порядок инициализации?

struct A { /* some definition */ }; 

typedef helper<int> s0; 
typedef helper<A> s1; 

Обрати внимание, что для ЬурейиХ helper<int>приходит перед в ЬурейеМ для helper<A>. Таким образом, согласно стандарту, я бы ожидал, что helper<int>::_data будет построен до helper<A>::_data (помните, что _data является статическим членом). На GCC это так, на Солнце это не так.

Это проблематично, поскольку конструктор A использует helper<int>::_data. У меня есть только одна единица компиляции, с более ранним потенциальным экземпляром helper<A>, поэтому я думал, что порядок должен быть четко определен. Является ли это ошибкой компилятора Sun, или же typedef не является технически определением/конкретизацией? Я имею в виду, является ли поведение компилятора Sun допустимым стандартом?

У меня есть следующие основные():

int main() 
{ 
    //Swapping the order of these has no effect on Sun 
    s0::foo(); 
    s1::foo(); 
} 

Там нет других видов использования s0 или s1.

ответ

6

В рамках одного и того же модуля компиляции стандарт C++ говорит, что статический порядок инициализации хорошо определен - это порядок объявлений статических объектов.

В показанном вами коде отсутствует объявление статического элемента данных. У вас есть объявление typedef-name. Они не имеют к этому никакого отношения и не влияют на какой-либо порядок. Вы, наверное, думаете по этому пути:

Если я сделать что ЬурейаЯ декларацию, это будет экземпляром helper<int>, и, таким образом, экземпляр его статическая декларации членов данных первым.

Проблема заключается в том, что эта строка не вызывает создание объекта helper<int>. Для этого вам понадобится явное создание экземпляра или удастся сделать его неявным образом (например, создав объект helper<int> или используя его в качестве вложенного спецификатора имен, как в helper<int>::..., и явно ссылаясь на статический член - в противном случае создание он опущен).

Но проблема гораздо глубже. Заказ составляет не объявление статических данных. Порядок: их определение. Рассмотрим следующий

struct C { C() { printf("hey\n"); } }; 
struct A { 
    static C a; 
    static C b; 
}; 

C A::b; 
C A::a; 

В этом коде б создается перед, даже если объявляется перед тем б.

следующие принты код 2 1:

struct C { C(int n) { printf("%d\n", n); } }; 

template<int N> 
struct A { 
    static C c; 
}; 

template<int N> 
C A<N>::c(N); 

// explicit instantiation of declaration and definition 
template struct A<2>; 
template struct A<1>; 

int main() { 

} 

Но следующий код печатает ничего, если не комментируют в строке в main.

struct C { C(int n) { printf("%d\n", n); } }; 

template<int N> 
struct A { 
    static C c; 
}; 

template<int N> 
C A<N>::c(N); 

// implicit instantiation of declarations 
A<2> a2; 
A<1> a1; 

int main() { 
    // A<1>::c; A<2>::c; 
} 

Я действительно не уверен, какой правильный результат для этого второго фрагмента. Читая Стандарт, я не могу определить заказ. Он говорит, что в 14.6.4.1 «Точке Инстанцирования»:

Для шаблона функции специализации функции члена специализации шаблона или специализации функции члена или статического член данных шаблона класса, если специализация неявно инстанцирована потому что на него ссылаются из другой специализированной специализации [...]. В противном случае точка инстанцирования для такой специализации немедленно следует за объявлением или определением области пространства имен, которое относится к специализации.

Пункт описания их определений появляется сразу после определения main. Какое определение создается до того, как другое определение остается неуказанным. Если кто-либо знает ответ и khow ведут себя другие компиляторы (GCC печатает 1 2, но с порядком выражений в main заменен, распечатывается 2 1), пожалуйста, дайте мне знать в комментарии.

Подробнее см. this answer about static object's lifetime.

+0

Спасибо за тщательный, информативный ответ. –

+0

К сожалению, если ваш ответ верен, и я правильно вас понимаю, то я думаю, что компилятор Sun по-прежнему не прав. В коде, следующем за исходным фрагментом, s1 :: something_using_the_static_member использовался до s0 :: something_using_the_static_member. Я переключил порядок, но Sun по-прежнему создает статический член s1 перед s0. Правильно ли я считаю? –

+0

См. Мое редактирование оригинального сообщения –

0

Вы фактически не объявляете никаких объектов в этом коде.

Вам нужен дополнительный код:

s0 one; 
s1 two; 

В этом случае два объекта теперь фактически объявлен, и должны работать правильно.

Вы явно объявляете s0?

Попробуйте следовать за typedefs с помощью s0 dummy; и посмотреть, устранена ли проблема.

+0

Из моего понимания кода * * объявляет объекты. помощник имеет статический элемент данных. Поэтому каждый раз, когда этот шаблон создается, создается статический элемент данных (объект). Шаблон typedef создает шаблон ... правильно? –

+0

typedef не создает экземпляр шаблона. –

+0

typedef ведет себя, по существу, как #define. –

Смежные вопросы