Comment avoir des données membres statiques dans une bibliothèque d'en-tête uniquement ?

StackOverflow https://stackoverflow.com//questions/11709859

  •  13-12-2019
  •  | 
  •  

Question

Quelle est la meilleure façon d'avoir un membre statique dans une classe de bibliothèque non compliquée, sans placer le fardeau de définir le membre de l'utilisateur de la classe?

Supposons que je souhaite proposer ce cours :

class i_want_a_static_member
{
    static expensive_resource static_resource_;

public:
    void foo()
    {
        static_resource_.bar();
    }
};

Alors l'utilisateur de la classe ne doit pas oublier de définir le membre statique quelque part (comme déjà répondu beaucoup fois):

// this must be done somewhere in a translation unit
expensive_resource i_want_a_static_member::static_resource_;

J'ai une réponse ci-dessous, mais elle présente certains inconvénients.Existe-t-il des solutions meilleures et/ou plus élégantes ?

Était-ce utile?

La solution

C++17 et supérieur

Utiliser inline static variables pour une initialisation non dynamique :

struct Foo
{
    inline static int I = 0;
};

Et utilisez les variables statiques locales de fonction sinon :

struct Foo
{
    static std::string& Bar()
    {
        static std::string S = compute();
        return S;
    }
};

C++14 et versions antérieures

Utilisez les fonctions statiques locales, car elles sont tout simplement plus faciles à utiliser.

Si pour une raison ou une autre vous souhaitez vraiment un affichage statique membre de données, alors vous pouvez utiliser l'astuce du modèle :

template <typename T = void>
struct Foo
{
     static int I = 0; // inline initialization only for simple types.
};

template <typename T>
int Foo<T>::I;

Sur la statique locale

Pour les ressources qui nécessitent une initialisation dynamique, il est préférable d'utiliser une statique locale.

L'ordre dans lequel les statiques de portée fichier ou de classe sont initialisées dynamiquement n'est pas défini, en général, ce qui conduit au fiasco de l'ordre d'initialisation statique lorsque vous essayez de lire une statique non initialisée dans le cadre de l'initialisation d'une autre.La statique locale résout le problème en étant initialisée paresseusement, lors de la première utilisation.

L'utilisation de statistiques locales entraîne cependant une légère surcharge.À partir de C++11, l'initialisation doit être thread-safe, ce qui signifie généralement que tout accès est contrôlé par une branche de lecture atomique et bien prédite.

Autres conseils

Ma propre solution consiste à utiliser une classe de titulaires modélisée, car les membres statiques fonctionnent bien dans des modèles et utilisent ce titulaire comme classe de base.

template <typename T>
struct static_holder
{
    static T static_resource_;
};

template <typename T>
T static_holder<T>::static_resource_;

Utilisez maintenant la classe de titulaire:

class expensive_resource { /*...*/ };

class i_want_a_static_member : private static_holder<expensive_resource>
{
public:
    void foo()
    {
        static_resource_.bar();
    }
};

Mais comme le nom du membre est spécifié dans la classe de titulaire, vous ne pouvez pas utiliser le même titulaire pour plus d'un membre statique.

A partir de C ++ 17. Vous pouvez maintenant utiliser des variables en ligne pour le faire:

static const inline float foo = 1.25f;

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top