0

据我所知,在任何人尝试使用这些对象之前,都需要调用全局对象的构造函数。但是在我的程序中似乎并非如此。这是我的简化代码(我用 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。

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

4

2 回答 2

4

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

此处相关的是 C++ 标准的第 3.6.2/2 节:

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

当然还有第 9.4.2/6 节,它指的是上述规则:

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

于 2013-01-24T23:54:20.840 回答
1

正在发生的事情是registrator<foo>::payloadtype_data_for_type<foo>::data. registrator<foo>然而,的构造函数使用type_data_for_type<foo>::data.

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

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

于 2013-01-25T00:27:58.233 回答