2010-09-13 12 views
12
#include <map> 
#include <iostream> 
template <typename T> 
class A 
{ 
static std::map<int, int> data; 
public: 
A() 
{ 
    std::cout << data.size() << std::endl; 
    data[3] = 4; 
} 
}; 

template <typename T> 
std::map<int, int> A<T>::data; 

//std::map<int, int> A<char>::data; 

A<char> a; 

int main() 
{ 
return 0; 
} 

¿Qué pasa con esto? Sin instanciación explícita se rompe en instancia de instancia estática de C++ plantilla

 data[3] = 4;
La instanciación explícita resuelve el problema pero el programa se rompe después de
std::cout << data.size() << std::endl;
lo que significa que la plantilla de clase estática memeber data se instancia.

+1

¿Qué compilador? No creo que esto sea tu culpa. – Potatoswatter

+0

Esto compila bien utilizando VS2010. – linuxuser27

+0

Estoy usando vs2008 y de hecho compila, pero el programa se rompe en los datos de línea [3] = 4 – mrs

Respuesta

2

No tengo a mano Visual C++, pero puedo ver el mismo problema con la compilación de código con GCC. Es necesario inicializar el miembro de datos:

template<> std::map<int, int> A<char>::data = std::map<int, int>(); 

Con este cambio, se compila y se ejecuta correctamente (para mí en GCC en Linux).

+0

Esto es necesario porque se necesita una instancia de datos separada para cada plantilla inicializada con un tipo diferente, en este char – Poorna

3

No hay instancias explícitas en su código.

No hay ningún orden de inicialización de los miembros de datos estáticos instanciados entre otros miembros de datos estáticos. Por lo tanto, su código tiene un comportamiento efectivamente indefinido: dependiendo de si el compilador inicializa primero el mapa o a, la referencia al mapa es válida o no.

Ver C++ Static member initialization.

+0

Probé std :: vector en lugar de mapa y todo funcionó bien sin instanciación explícita: crees que es solo suerte ? – mrs

+0

y es curioso que en este ejemplo la primera línea en el constructor std :: cout << data.size() << std :: endl; funciona como se esperaba; el programa se rompe cuando intento insertar algo en el mapa – mrs

+0

Esa "instanciación explícita" no es una creación de instancias explícita. Es la definición de un miembro de datos estáticos llamado 'datos' de una especialización explícita de la plantilla' A' para 'T = char'. No hay tal especialización explícita. El compilador debe emitir un mensaje de error para ese código (si lo comenta). –

1

Existen varios errores en ese código. Primero, la idea inicial no es buena. Tiene dos objetos estáticos globales: a y A::data. El orden en que se inicializaron no está definido. Dependiendo del estado de ánimo de su compilador, tiene un 50% de posibilidades de que el constructor de a se llame primero e intente escribir algo en el A::data no inicializado.

Esto a veces se llama problema static init order fiasco. Una solución propuesta es convertir estos objetos en objetos estáticos locales moviéndolos en funciones:

#include <map> 
#include <iostream> 

template <typename T> 
class A 
{ 
    std::map<int, int> &data() 
    { 
    static std::map<int, int> d; 
    return d; 
    } 
public: 
    A() 
    { 
    std::cout << data().size() << std::endl; 
    data()[3] = 4; 
    } 
}; 

int main() 
{ 
    A<char> a; 
    return 0; 
} 

objetos estáticos locales son inicializados en la primera llamada a la función.

Acerca de la "instanciación explícita" comentada que olvidó template <>.

Pero después de escribir antes de esa línea con template <> que todavía no definición sino una declaración. Declara que existe la definición de datos A :: en otro lugar. Para definirlo realmente necesitas inicializarlo con algo, ver respuesta de Jack Lloyd por ejemplo.

Cuestiones relacionadas