如何避免延迟静态存储时长变量的初始化?

How to avoid deferring the initialization of static storage duration variables?

提问人:Dmitry Kuzminov 提问时间:5/4/2023 最后编辑:Dmitry Kuzminov 更新时间:5/5/2023 访问量:170

问:

我的构造函数中有副作用的类,这些类的对象是具有静态存储持续时间的全局对象。在初始化期间,这些对象在特殊映射中注册其类,在将此映射用于其他目的之前,必须进行这些注册。

类及其全局对象在单独的转换单元中定义,并且根据非块变量的动态初始化规则,初始化可以延迟到使用这些转换单元中的其他函数或变量,这可能意味着初始化被无限期延迟。

我正在寻找一种方法来避免这些全局对象的延迟初始化。说我的意思是对象的构造函数应该在它开始之前或之后被调用,但所有的更改都应该在这些对象的转换单元内完成。换言之,每当再添加一个具有全局对象的翻译单元时,不得修改其他翻译单元。main

更新:下面是一个示例:

struct Base {
};

extern void regFactoryMethod(std::function<std::shared_ptr<Base>()>);

struct Object : Base {
    struct Registrator {
        Registrator() {
            regFactoryMethod([](){ return std::make_shared<Object>(); });
        }
    };
    static Registrator registrator;
};

Object::Registrator Object::registrator;

这个想法是自动调用的。但不能保证它会,因为此调用可能会被推迟:Object::Registrator::Registrator()

它是实现定义的,动态初始化是否 静态存储持续时间为 在 main 或的第一个语句之前排序,是延迟的。如果是 延迟,它强烈发生在任何非初始化 ODR 使用 任何非内联函数或在其中定义的非内联变量 翻译单元作为要初始化的变量。是的 实现定义了哪些线程以及 程序发生这种延迟的动态初始化。

C++ 副作用 静态初始化 存储持续时间 翻译单元

评论

1赞 Dmitry Kuzminov 5/4/2023
@paddy,该问题与静态初始化顺序惨败有关,但并不完全相同。就我而言,我不关心顺序,但我需要确保初始化完成,直到调用某些代码。而且我不能使用“getters”,因为客户端代码不知道所有需要初始化的对象。反之亦然:一些对象本身需要举起一个标志:“INITIALIZE ME”,而客户端代码需要强制系统初始化所有举起旗帜的人(但它甚至不知道谁)。
1赞 Dmitry Kuzminov 5/4/2023
班级工厂将如何提供帮助?我在新的翻译单元中添加了一个新类,而无需更改任何其他代码。班级工厂如何知道新班级?
1赞 Dmitry Kuzminov 5/4/2023
@AviBerger,代理的构建是无法保证的,因为它可以无限期推迟。
1赞 Dmitry Kuzminov 5/4/2023
“它是实现定义的,具有静态存储持续时间的非块非内联变量的动态初始化是在 main 的第一个语句之前排序还是延迟。如果它被延迟,则在与要初始化的变量相同的转换单元中定义的任何非内联函数或非内联变量的任何非初始化 odr 之前,它强烈发生。它是实现定义的,在程序中的哪些线程和哪些点发生这种延迟的动态初始化。
1赞 Peter 5/4/2023
AFAIK,您寻求的保证(执行静态存储持续时间的所有对象的构造函数,即使没有调用与对象相同的转换单元中定义的函数)是不可行的。不理想,但如果无法满足需求,则必须更改需求(例如,允许修改另一个翻译单元,以包含新的类型定义并定义该类型的静态对象。通过自动构建相关类型的列表并生成“其他”翻译单元并在构建过程中重新编译它,可以简化该过程。

答:

-1赞 user17732522 5/4/2023 #1

正如您在问题中所指出的,动态初始化是直接还是间接地通过 .main

在输入之前,也没有其他标准方法来执行代码。main

所以,我认为你不能得到一个独立于实现的保证。该标准还涵盖了一些用例,例如在运行时动态加载库,例如使用 .在这些情况下,在输入之前无法执行库中包含的代码。dlopenmain

您必须寻找实施保证或实施特定功能。比如Linux上的GCC/binutils,只要你不链接,,等,而你忽略,我认为不会有任何延迟初始化。--as-needed--gc-sectionsdlopen

评论

0赞 Dmitry Kuzminov 5/5/2023
我的目标不是在主之前执行代码,而是在任何预测的时刻之前执行它。
1赞 user17732522 5/5/2023
@DmitryKuzminov “预测时刻”是什么意思?
1赞 user17732522 5/5/2023
@DmitryKuzminov但这并不重要。如果不引用该转换中定义的实体的声明,则不可能将控制权从 的执行转移到另一个转换单元中的任何代码,或者通过其他转换单元传递,假设该转换单元之前未在执行的代码中被引用。mainmain
0赞 Dmitry Kuzminov 5/5/2023
到目前为止,问题在于代码可能永远不会被执行。
0赞 user17732522 5/5/2023
@DmitryKuzminov 理论上是的,但你真的在某些实现中看到这种行为了吗?如果是这样,您将该程序与哪些选项链接在一起?它是实现定义的,而不是未指定的