web-dev-qa-db-fra.com

Ordre d'initialisation des membres en ligne statique

Un problème bien connu en C++ est le FIASCO d'ordre d'initialisation statique . Est-il toujours considéré comme un problème lorsque vous utilisez C++ 17 Membres statiques en ligne statiques?

Ici, un exemple où un membre en ligne statique est utilisé dans deux unités de traduction différentes (A.CPP et B.CPP) en tant qu'indialisateur pour deux membres statiques non lignés:

compteur.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() { }

Sortie (avec 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

Je pense que, en ce qui concerne l'initialisation, cette pratique est sûre car la norme C++ 17 garantit que les membres en ligne statiques sont les suivants: (1) toujours initialisé avant toute utilisation et (2) initialisée uniquement une fois sur plusieurs unités de traduction.

Mais j'aimerais savoir s'il y a des descentes cachées dans ce modèle, par exemple lié à l'ordre de destruction de chaque variable à travers différents TU. Est-il bien défini que les deux static_a et static_b sont toujours détruits avant static_counter?

4
Tarquiscani

Oui, c'est bien, car dans chaque unité de traduction static_counter est défini avantstatic_a/static_b. L'ordre de destruction n'est pas garanti d'être l'inverse (des threads donnés, cela ne signale de toute façon), mais le Reverse de chaque garantie contient , de sorte que cela fonctionne également.

1
Davis Herring