静态内联成员初始化顺序

Tar*_*ani 5 c++ static-initialization c++17

C++ 中一个众所周知的问题是静态初始化顺序失败。当使用C++17 静态内联成员时,它仍然被认为是一个问题吗?

这是一个示例,其中静态内联成员在两个不同的翻译单元(a.cpp 和 b.cpp)中用作两个非内联静态成员的初始化程序:

计数器.hh

#pragma once

#include <vector>
#include <fstream>

class Counter
{
    public:
        Counter()  { std::ofstream os("o.txt", std::ofstream::app); os << "Counter created" << std::endl; }
        ~Counter() { std::ofstream os("o.txt", std::ofstream::app); os << "Counter destroyed" << std::endl; }
        void add_instance()    
        { 
            ++m_instances; 
            std::ofstream os("o.txt", std::ofstream::app); os << "Counter increased: " << m_instances << std::endl; 
        }
        void remove_instance() 
        { 
            --m_instances; 
            std::ofstream os("o.txt", std::ofstream::app); os << "Counter decreased: " << m_instances << std::endl; 
        }

    private:
        int m_instances = 0;
};

class Object
{
    public:
        Object(Counter & counter) : m_counter(counter) 
        {
            m_counter.add_instance(); 
            std::ofstream os("o.txt", std::ofstream::app); os << "Object created" << std::endl; 
        }
        ~Object() 
        { 
            m_counter.remove_instance(); 
            std::ofstream os("o.txt", std::ofstream::app); os << "Object destroyed" << std::endl; 
        }

    private:
        Counter & m_counter;
};

struct C
{
    static inline Counter static_counter{};
};
Run Code Online (Sandbox Code Playgroud)

啊啊啊啊

#pragma once

#include "counter.hh"

struct A
{
    static Object static_a; //not inline
};
Run Code Online (Sandbox Code Playgroud)

a.cpp

#include "a.hh"

Object A::static_a{C::static_counter};
Run Code Online (Sandbox Code Playgroud)

b.hh

#pragma once

#include "counter.hh"

struct B
{
    static Object static_b; //not inline
};
Run Code Online (Sandbox Code Playgroud)

b.cpp

#include "b.hh"

Object B::static_b{C::static_counter};
Run Code Online (Sandbox Code Playgroud)

主程序

#include "a.hh"
#include "b.hh"

int main() { }
Run Code Online (Sandbox Code Playgroud)

输出(使用 MSVC 16.1.2)

Counter created
Counter increased: 1
Object created
Counter increased: 2
Object created
Counter decreased: 1
Object destroyed
Counter decreased: 0
Object destroyed
Counter destroyed
Run Code Online (Sandbox Code Playgroud)

我认为,关于初始化,这种做法是安全的,因为 C++17 标准确保静态内联成员是:(1) 在任何使用之前总是初始化和 (2) 在多个翻译单元中只初始化一次。

但我想知道这种模式是否存在任何隐藏的缺点,例如与跨不同 TU 的每个变量的销毁顺序有关。static_astatic_b总是在之前被销毁是否明确定义static_counter

Dav*_*ing 2

是的,这很好,因为每个翻译单元static_counter都是在/之前定义的 。销毁顺序不保证是相反的(给定线程,这无论如何都是没有意义的),但是每个保证的相反都成立,所以这也有效。static_astatic_b