2012-09-06 15 views
14

Sto sviluppando una libreria composta solo da file di intestazione. Finora, contiene solo classi, che sono andate bene. Tuttavia, sono giunto al punto in cui ho bisogno di avere alcuni dati immutabili accessibili in tutta la biblioteca nella libreria (cioè non dati di istanze di classe) per l'implementazione di alcune funzioni. Ovviamente non puoi semplicemente inserire i dati globali nei file di intestazione, altrimenti ogni unità di compilazione che ha l'intestazione #include avrà una definizione per il simbolo e avrai più errori di definizione al momento del collegamento.Dati statici nelle librerie di sola intestazione

Mi sembra di aver trovato una soluzione che mi consente di avere dati statici in una classe senza dover aggiungere un'unità di compilazione alla libreria semplicemente rendendo i dati una variabile static in una funzione e restituendo un puntatore a quei dati:

class StaticData { 
public: 
    void doSomething() { /* this uses getData */ } 
    void doSomethingElse() { /* this does too */ } 

private: 
    static int* getData() { 
     static int array[] { 1, 2, 3, 4 }; 

     return array; 
    } 
}; 

Questo sembra funzionare bene, ma devo ammettere che non so cosa succede ai FUNCTION- static dati in inline funzioni nei file di intestazione. Mi chiedo se questo "hack" abbia qualche ripercussione involontaria, come ogni unità di compilazione che #include s questa intestazione ottiene la propria versione di array. Come e dove decide di metterlo il compilatore?

Inoltre va osservato che non sto usando questo per implementare l'antipattern singolo o nulla. Lo sto solo usando per immagazzinare dati che molte funzioni dovranno usare (ecco perché non può essere static solo in una funzione che lo usa, ma anche se lo facesse, ciò richiederebbe la stessa domanda).

risposta

9

Questo va bene. È garantito che ci sarà una sola copia di array, a condizione che la funzione abbia un collegamento esterno, cosa che fa. Lo standard C++ dice:

7.1.2/4 Una variabile locale statica in una funzione inline esterna fa sempre riferimento allo stesso oggetto.

+0

Ah, che è un sollievo. Presumo che questo vale per C++ 03 e C++ 11? Questo risponde alla mia domanda per scopi pratici, ma solo per divertimento, ci sono informazioni indipendenti dall'implementazione su come il compilatore decide dove mettere la definizione di dati/funzione? –

+0

C++ 03 ha esattamente la stessa formulazione. Credo che i compilatori impostino una bandiera sui simboli per le funzioni inline e i loro locals statici, o li inseriscano in sezioni speciali, per dire al linker di includere la prima occorrenza che trova e scartare i duplicati. Ma non conosco alcun dettaglio al riguardo. –

0

Un altro approccio ...

template<typename> class ArrayData { 
    friend class ClassWithArray; 
    static int array[4]; 
}; 

class ClassWithArray : 
    ArrayData<ClassWithArray> 
{ 
public: 
    void doSomething() { 
     /* this uses getData */ 
     array[0] = 1; 
     array[1] = 2; 
     array[2] = 3; 
     array[3] = 4; 
    } 
    void doSomethingElse() { 
     /* this does too */ 
     array[0] = 4; 
     array[1] = 3; 
     array[2] = 2; 
     array[3] = 1; 
    } 
}; 

int ArrayData<ClassWithArray>::array[4] = { 1, 2, 3, 4 }; 

generico implementazione

template<typename T> class ArrayDataT 
{ 
    friend T; 
    static int array[4]; 
}; 

template<typename T> 
int ArrayDataT<T>::array[4] = { 1, 2, 3 ,4 }; 

class DerivedFromArrayDataT : 
    ArrayDataT<DerivedFromArrayDataT> 
{ 

};