Domanda

Qual è il modo migliore per avere un membro statico in una classe di biblioteca non modellata, Senza collocare il peso della definizione del membro dell'utente della classe?

Dì che voglio fornire questa classe:

class i_want_a_static_member
{
    static expensive_resource static_resource_;

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

Allora l'utente della classe non deve dimenticare di definire il membro statico da qualche parte (come già Risposta Molti Times ):

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

Ho una risposta qui sotto, ma ha alcuni svantaggi.Ci sono soluzioni migliori e / o più eleganti?

È stato utile?

Soluzione

C ++ 17 e oltre

Utilizzare variabili inline static per l'inizializzazione non dinamica:

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

e utilizzare le variabili statiche locali locali altrimenti:

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

C ++ 14 e sotto

Utilizzare la funzione statica locale, poiché sono semplici facili da usare.

Se per qualche motivo desideri davvero un membro di dati statico , è possibile utilizzare il trucco del modello:

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

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

su Statics locale

Per le risorse che richiedono l'inizializzazione dinamica, è meglio usare una statica locale.

L'ordine in cui la statica del file-scope o dell'ambito della classe viene inizializzata dinamicamente è indefinita, in generale, portando all'ordine di inizializzazione statistico Fiasco quando si tenta di leggere una statica non inizializzata come parte dell'inizializzazione di un altro. La statica locale risolve il problema essendo inizializzato pigramente, al primo uso.

C'è un leggero sovraccarico per usare la statica locale, tuttavia. Da C ++ 11 in poi, l'inizializzazione è richiesta per essere cassaforte con filettatura, che in genere significa che qualsiasi accesso è gated da un ramo a lettura atomica e ben previsto.

Altri suggerimenti

La mia soluzione è quella di utilizzare una classe Holder Templated, poiché i membri statici funzionano bene nei modelli, e utilizzare questo supporto come classe base.

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

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

Ora usa la classe titolare:

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

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

Ma poiché il nome del membro è specificato nella classe titolare, non è possibile utilizzare lo stesso supporto per più di un membro statico.

A partire da C ++ 17. Ora puoi utilizzare le variabili in linea per fare ciò:

static const inline float foo = 1.25f;
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top