2012-09-06 6 views
14

Estoy desarrollando una biblioteca que constará únicamente de archivos de encabezado. Hasta ahora, contiene solo clases, lo cual ha estado bien. Sin embargo, llegué a un punto en el que necesito tener acceso a toda la biblioteca de datos invariables en la biblioteca (es decir, no datos de instancia de clase) para la implementación de algunas funciones. Obviamente, no puede simplemente poner datos globales en archivos de encabezado, o de lo contrario, cada unidad de compilación que tenga #include s tendrá una definición para el símbolo y obtendrá múltiples errores de definición en tiempo de enlace.Datos estáticos en bibliotecas de solo encabezado

Parece que he encontrado una solución que me permite tener datos estáticos en una clase sin tener que agregar una unidad de compilación a la biblioteca simplemente haciendo que los datos sean una variable static en una función y devuelvan un puntero a esos datos:

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; 
    } 
}; 

Esto parece estar funcionando bien, pero hay que admitir que no sé lo que ocurre con Función- static datos en inline funciones en archivos de cabecera. Me pregunto si este "truco" tiene alguna repercusión involuntaria, como cada unidad de compilación que #include s este encabezado obtiene su propia versión de array. ¿Cómo y dónde decide el compilador ponerlo?

También debe tenerse en cuenta que no estoy usando esto para implementar el antipatrón singleton o algo. Solo lo estoy usando para almacenar datos que varias funciones necesitarán usar (por lo que no puede ser static en una función que lo use, pero incluso si lo hiciera, eso provocaría la misma pregunta).

Respuesta

9

Eso está bien. Se garantiza que solo habrá una copia de array, siempre que la función tenga un enlace externo, lo que hace. El estándar de C++ dice:

7.1.2/4 Una variable local estática en una función externa en línea siempre se refiere al mismo objeto.

+0

Ah, eso es un alivio. ¿Supongo que esto se aplica a C++ 03 y C++ 11? Esto responde mi pregunta con propósitos prácticos, pero solo por diversión, ¿hay alguna información independiente de la implementación sobre cómo el compilador decide dónde colocar la definición de datos/funciones? –

+0

C++ 03 tiene exactamente la misma redacción. Creo que los compiladores marcan los símbolos para las funciones en línea y sus locales estáticos, o los colocan en secciones especiales, para indicar al vinculador que incluya la primera ocurrencia que encuentra y descarta los duplicados. Pero no sé ningún detalle sobre eso. –

0

Otro enfoque ...

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 }; 

implementación genérica

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> 
{ 

}; 
Cuestiones relacionadas