首次使用对象后调用的全局对象构造函数

时间:2013-01-24 23:38:12

标签: c++ gcc constructor global

据我所知,在任何人尝试使用这些对象之前,需要调用全局对象的构造函数。但是在我的程序中,情况似乎并非如此。这是我的简化代码(我用gcc版本4.6.3-1ubuntu5编译)

#include <iostream>

using namespace std;

struct type_data
{
    int id;

    type_data()
        : id(-1) // set some invalid id
    {
        cout << "creating a new type data" << endl;
    }
};

template <typename T>
struct type_data_for_type
{
    static type_data data;
};
template <typename T>
type_data type_data_for_type<T>::data;


struct type_registry
{
    static type_registry& instance()
    {
        static type_registry i;
        return i;
    }

    void register_type(type_data& t)
    {
        cout << "registering a type" << endl;
        t.id = last_id++;
    }

    int last_id;
};

template <typename T>
struct registrator
{
    registrator()
    {
        type_registry::instance().
            register_type(type_data_for_type<T>::data);
    }

    int unused;
    static registrator payload;
};
template <typename T>
registrator<T> registrator<T>::payload;

class foo {};

inline void register_foo()
{
    registrator<foo>::payload.unused = 1;
}

int main()
{
    cout << type_registry::instance().last_id << endl;
    cout << type_data_for_type<foo>::data.id << endl;
    return 0;
}

基本上它通过register_foo全局注册foo类型。我希望输出为:

creating a new type data
registering a type
1
0

但它是:

registering a type
creating a new type data
1
-1

这意味着我在调用构造函数之前设置了type_data对象的id。

那么,这是一个编译器错误吗?我错过了什么吗?我可以做这个工作吗?

2 个答案:

答案 0 :(得分:4)

我相信在这种情况下你不能依赖类模板的静态成员变量的初始化顺序。

这里的相关内容是C ++标准的第3.6.2 / 2节:

*“具有静态存储持续时间的非局部变量的动态初始化是有序的或 无序的。显式专用类模板的定义静态数据成员已经有序初始化。 其他类模板静态数据成员(即隐式或显式实例化的特化)* 具有无序初始化 。“

当然还有§9.4.2/ 6,它引用了上述规则:

“静态数据成员的初始化和销毁​​与非局部变量(3.6.2,3.6.3)完全相同。”

答案 1 :(得分:1)

正在发生的事情是registrator<foo>::payloadtype_data_for_type<foo>::data之前被初始化。但是,registrator<foo>的构造函数使用type_data_for_type<foo>::data

您不能依赖于以任何特定顺序调用的静态初始化程序,并且在您的情况下,它与您想要的顺序完全错误地发生。

我认为根本问题在于您的解决方案过于复杂。您真的需要区分type_data_for_typeregistrator吗?类型数据对象不能自己注册吗?