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

Global objects constructors called after first use of object

本文关键字:对象 全局 构造函数 调用      更新时间:2023-10-16

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

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

我相信

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

与此相关的是C++标准的§ 3.6.2/2:

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

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

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

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

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

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