Статическая переменная из статической связанной библиотеки, используемой до ее создания

Я пытался создать для себя фреймворк модульного тестирования, и он работал нормально, пока я не превратил его в статическую библиотеку. Статический контейнер unit_base :: _ units используется до его создания.

Я воспроизвел проблему со следующей более простой версией:

lib.lib

lib.h

#pragma once

#include <vector>
namespace est {
    class unit_base
    {
    public:
        unit_base();
        class unit_vec : public std::vector<unit_base*> {
        public:
            unit_vec();
            ~unit_vec();
        };
        static unit_vec& get_units();
        virtual bool run() const = 0;
    private:
        static unit_vec _units;
    };

    bool test_all();
}

lib.c

#include "lib.h"
#include <iostream>

namespace est {
    unit_base::unit_vec unit_base::_units;
    unit_base::unit_base() {
        _units.push_back(this);
        std::cout << "push unit to: " << &_units << std::endl;
    } 
    unit_base::unit_vec::unit_vec() {
        std::cout << "vec(): " << this << std::endl;
    }
    unit_base::unit_vec::~unit_vec() {
        std::cout << "~vec(): " << this << std::endl;
    }
    unit_base::unit_vec& unit_base::get_units()
    {
        return _units;
    }
    bool test_all()
    {
        std::cout << "before get_units" << std::endl;
        auto& units = unit_base::get_units();
        std::cout << "after get units" << std::endl;
        for(auto& u: units) {
            u->run();
        }
        return false;
    }
}

exe

test.cpp

#include "lib.h"
#include <iostream>

namespace est
{
    bool est_test_func();
    class est_test : public unit_base
    {
    public:
        est_test():
            unit_base() {}
        bool run() const override
        {
            return est_test_func();
        }
    };
    static est_test est_test_inst;
    bool est_test_func() {
        std::cout << "test" << std::endl;
        return true;
    }
}

int main(int argc, char** argv)
{
    est::test_all();
}

EXE печатает:

нажмите на единицу: 0x7f72dc873170
vec (): 0x7f72dc873170
перед get_units
после получения единиц
~ vec (): 0x7f72dc873170

Я тестировал его в Windows и WSL, и оба результата дали пустые _units для test_all (). Я, должно быть, делаю что-то ужасно неправильно, поэтому я здесь за помощью.

Я создал репо с CMakeLists: https://github.com/Lucipetus/problemic.git


person 杨Eugene    schedule 18.04.2021    source источник
comment
У вас есть две разные единицы перевода, которые создают экземпляры объектов в статической области видимости, между которыми существует определенная зависимость. К сожалению, C ++ не гарантирует статический порядок инициализации в разных единицах перевода, см. Связанный вопрос для получения дополнительной информации.   -  person Sam Varshavchik    schedule 18.04.2021
comment
Спасибо! Я наивно ожидал, что статические переменные будут инициализированы прямо перед доступом, по крайней мере, когда моя программа была статически связана вместе (это действительно работало, когда я создавал исходные коды как одну программу). Я должен проверить стандарты @ SamVarshavchik   -  person 杨Eugene    schedule 18.04.2021