【问题标题】:Initialization order of static inline member variables in class templates (C++17)类模板中静态内联成员变量的初始化顺序(C++17)
【发布时间】:2022-09-17 04:06:49
【问题描述】:

我正在编写一个代码,我需要使用类模板实例的静态变量来初始化某个类的静态成员变量。我知道静态初始化顺序惨败,并发现了几个关于该问题的讨论,但没有一个真正帮助我解决我的问题。我什至不知道为什么这对我来说是个问题。

这是一个最小的示例,它重现了我从代码中得到的错误:

#include <string>
#include <map>


template<class T>
class Foo {

private:

    static inline std::map<std::string, T> map_ = {};
    
public:
    
    static bool insert(const std::string& key, T value) {

        map_[key] = value;
        return true;
    }
};


using MyFoo = Foo<char>;

class Bar {
    static inline bool baz_ = MyFoo::insert(\"baz\", \'A\');
};


int main() {
    // This works just fine if the definition of Bar::baz_ in line 24 is removed
    //MyFoo::insert(\"baz\", \'A\');
    return 0;
}

使用 C++17 标准的编译以 0 个警告和 0 个错误结束。但是,在执行程序时,调用Foo::insert 时会发生分段错误。看来Foo::map_ 那时还没有初始化。但是不应该按照代码中定义的顺序来初始化静态变量吗?

我还应该提到,没有模板的代码可以正常工作。所以我想知道编译器是否以在Bar 之后定义实际类的方式实例化模板。可能是这样的问题还是编译器在这种情况下恰好做了“正确”的事情?

    标签: c++ templates static c++17 inline


    【解决方案1】:

    类模板特化的静态数据成员的动态初始化(如果它们没有显式特化)与任何其他动态初始化完全无序(不确定顺序)。成员是否为inline无关紧要,其他动态初始化是否也是类模板特化的静态数据成员无关紧要,点在哪里也无关紧要静态数据成员的实例化和定义位于翻译单元中。

    因此无法保证Foo&lt;char&gt;::map_Bar::baz_ 之前初始化。

    而是使用使用包含静态成员作为本地 static 变量的静态成员函数的常见习惯用法:

    static auto& map_() {
        static std::map<std::string, T> map = {};
        return map;
    }
    
    // replace `map_` with `map_()` everywhere else
    

    【讨论】:

    • 所以它确实与类模板有关。非常感谢您的解释。您提出的解决方案非常有效!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 2011-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多