2009-07-10 43 views
3

在同一个编译单元中,C++标准指出静态初始化顺序已被很好地定义 - 它是静态对象声明的顺序。但是使用Sun Studio 12编译器时遇到了直觉行为。我已经定义了一个模板类helper<T>,其中包含T类型的静态成员_data以及使用_data(调用foo)的静态成员函数。在我的.cpp文件我有这个上面的main():模板的typedefs是否保存静态初始化顺序?

struct A { /* some definition */ }; 

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

注意,对于helper<int> typedef的自带之前helper<A> typedef的。因此根据标准,我预计helper<int>::_data将在helper<A>::_data之前构建(记住_data是一个静态成员)。在GCC上就是这样,在Sun上它不是。

这是有问题的,因为A的构造函数使用helper<int>::_data。我只有一个编译单元,没有更早的helper<A>潜在实例,所以我认为应该定义好顺序。这是Sun编译器的bug,还是typedef在技术上不构成定义/实例?我的意思是,标准允许Sun编译器的行为?

我主要有如下():

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

有的S0或S1没有其​​他用途。

回答

6

在同一个编译单元中,C++标准指出静态初始化顺序已被很好地定义 - 它是静态对象声明的顺序。

在您显示的代码中,您没有声明静态数据成员。你有一个typedef-name的声明。这些与此无关,也不影响任何订单。 你可能想沿着这样

如果我作出这样的typedef声明,它将实例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; 

在这段代码,B是之前创建的,即使A是B之前声明。

下面的代码打印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其他编译器的行为(海湾合作委员会打印1 2,但表达式的顺序main交换,打印2 1),请让我知道在评论中。

有关详细信息,请参见this answer about static object's lifetime

0

你实际上并没有在该代码中声明任何对象。

你需要额外的代码:

s0 one; 
s1 two; 

在这种情况下,这两个对象现在实际上宣告,并应能正常工作。

您是否明确声明了s0?

尝试跟一个s0虚拟类型定义;并查看问题是否得到解决。

+0

从我的理解代码*不*声明对象。帮手有一个静态数据成员。所以每当模板被实例化时,都会创建一个静态数据成员(一个对象)。 typedef实例化模板....对吧? – 2009-07-10 16:03:37

+0

typedef没有实例化模板。 – 2009-07-10 16:05:09

相关问题