如果对象是在库中定义的,为什么静态创建的对象的构造函数不会在 main 函数之前执行?

Why constructor of a statically created object is not executed before main function if the object is defined in library?

提问人:KajzerSoze 提问时间:10/19/2023 最后编辑:KajzerSoze 更新时间:10/19/2023 访问量:85

问:

我正在尝试创建“插件”工厂。当用户请求创建对象工厂时,会查询其子工厂,并选择合适的子工厂来创建对象。

子库的实例是静态对象。创建后,它们将自己注册到顶级工厂。

以下是简化版本:

// ifactory.h
#ifndef _IFACTORY_H_
#define _IFACTORY_H_

#include <string>

class IFactory {
public:
    virtual int createNumber(const std::string& name, std::pair<int, int> range) = 0;

    virtual std::string getName() const = 0;

    virtual ~IFactory() = default;
};

#endif
// defaul_factory.h:
#ifndef _DEFAULT_FACTORY_H_
#define _DEFAULT_FACTORY_H_

#include "ifactory.h"

#include <vector>
#include <stdexcept>

class DefaultFactory : public IFactory {
public:
    int createNumber(const std::string& name, std::pair<int, int> range) override {
        for (auto factory: g_factories) {
            if (factory->getName() == name) {
                return factory->createNumber(name, range);
            }
        }

        throw std::runtime_error{"No factory can create requested number"};
    }

    std::string getName() const override {
        return "default";
    }

    static void registerFactory(IFactory* factory) {
        g_factories.push_back(factory);
    }

private:
    static std::vector<IFactory*> g_factories;
};
#endif
// defalut_factory.cpp
#include "default_factory.h"

std::vector<IFactory*> DefaultFactory::g_factories;
// even_factory.cpp
#include "default_factory.h"

class EvenFactory : public IFactory {
public:
    EvenFactory() {
        DefaultFactory::registerFactory(this);
    }

    int createNumber(const std::string& name, std::pair<int, int> range) override {
        return range.first % 2 == 0 ? range.first + 4 : range.first + 3;
    }

    std::string getName() const override {
        return "even";
    }
};

// Hopefully registers itself to the default factory
static EvenFactory evenFactory;
// main.cpp
#include "default_factory.h"

#include <iostream>

int main() {
    DefaultFactory factory;
    std::cout << factory.createNumber("even", {100, 200}) << std::endl;
}
# Makefile:
all: foo

foo: libdefault_factory.so libeven_factory.so main.cpp
    $(CXX) -L./ -o foo main.cpp -ldefault_factory -Wl,--no-as-needed -leven_factory

libdefault_factory.so: default_factory.cpp default_factory.h ifactory.h
    $(CXX) -shared -fPIC -o libdefault_factory.so default_factory.cpp

libeven_factory.so: even_factory.cpp default_factory.h ifactory.h
    $(CXX) -shared -fPIC -o libeven_factory.so even_factory.cpp

bar: default_factory.cpp even_factory.cpp default_factory.h ifactory.h main.cpp
    $(CXX) -o bar main.cpp default_factory.cpp even_factory.cpp

.PHONY: clean

clean:
    rm foo bar *.so

当我执行时,我得到一个运行时异常,该异常是从 抛出的,就好像构造函数没有运行一样。fooDefalutFactoryevenFactory

按预期运行打印。bar104

为什么不为构造函数调用?foo

注意:我使用 g++ 版本 9 和 g++ 版本 10.2 测试了该示例。

C++ 方法 静态 变量 抽象工厂

评论

0赞 user4581301 10/19/2023
代码中不同错误的解释:在 C++ 标识符中使用下划线的规则是什么?
0赞 Jarod42 10/19/2023
请参见Deferred_dynamic_initialization
3赞 n. m. could be an AI 10/19/2023
-leven_factory什么也不做。库外部的任何对象都引用该库中的任何内容,因此它根本没有链接。你想要之前.(通过运行 进行验证)。(我认为 --no-as-needed 曾经是默认设置,但 Ubuntu 和其他可能的人最近改变了这一点)。-Wl,--no-as-needed-leven_factoryldd foo
4赞 Miles Budnek 10/19/2023
欢迎来到静态初始化订单惨败。 可以在 之前构建。C++ 不保证不同翻译单元中的静态对象初始化的顺序。evenFactoryg_factories
1赞 n. m. could be an AI 10/19/2023
@Jarod42主流平台上的AFAIK主流编译器不进行延迟初始化,如果开始进行延迟初始化,很多现有代码就会中断。所以他们可能永远不会。至少默认情况下不是。

答: 暂无答案