静态内联成员初始化顺序

时间:2019-06-09 14:18:22

标签: c++ c++17 static-initialization

在C ++中,一个众所周知的问题是static initialization order fiasco。当人们使用 C ++ 17静态内联成员

时,它仍然被认为是一个问题吗?

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

counter.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{};
};

a.hh

#pragma once

#include "counter.hh"

struct A
{
    static Object static_a; //not inline
};

a.cpp

#include "a.hh"

Object A::static_a{C::static_counter};

b.hh

#pragma once

#include "counter.hh"

struct B
{
    static Object static_b; //not inline
};

b.cpp

#include "b.hh"

Object B::static_b{C::static_counter};

main.cpp

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

int main() { }

输出(使用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

我认为,对于初始化而言,这种做法是安全的,因为C ++ 17标准可确保静态内联成员:(1)始终在使用前初始化,以及(2)在多个翻译单元中仅初始化一次

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

1 个答案:

答案 0 :(得分:1)

是的,这很好,因为在每个翻译单元中,static_counterdefined before static_a / static_b。不能保证销毁顺序是相反的(给定线程,无论如何这是没有意义的),但是可以保证reverse of each guarantee holds的销毁顺序是相反的。