2010-09-13 4 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; 
} 

Quel est le problème avec cela? Sans instanciation explicite, il casse à C++ modèle membre statique instantiation

 data[3] = 4;
L'instanciation explicite résout le problème mais le programme se brise après
std::cout << data.size() << std::endl;
ce qui signifie que le modèle de classe statique memeber data a été instancié.

+1

Quel compilateur? Je ne pense pas que ce soit ta faute. – Potatoswatter

+0

Cela compile bien en utilisant VS2010. – linuxuser27

+0

J'utilise vs2008 et il compile en effet mais le programme se casse aux données de ligne [3] = 4 – mrs

Répondre

2

Je n'ai pas Visual C++ à portée de main, mais je peux voir le même problème avec votre code de compilation avec GCC. Vous avez besoin de l'initialiser les données membre:

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

Avec ce changement, il compile et fonctionne correctement (pour moi sur GCC sous Linux).

+0

Est-ce nécessaire car une instance distincte de données est nécessaire pour chaque template initialisé avec un type différent, dans ce char – Poorna

3

Il n'y a pas d'instanciation explicite dans votre code.

Il n'y a pas d'ordre d'initialisation des membres de données statiques instanciés parmi les autres membres de données statiques. Votre code a donc un comportement non défini: selon que le compilateur initialise la carte ou a, la référence à la carte est valide ou non.

Voir C++ Static member initialization.

+0

J'essayais std :: vector au lieu de map et tout fonctionnait bien sans instanciation explicite - vous pensez que c'est juste de la chance ? – mrs

+0

et c'est marrant que dans cet exemple la première ligne du constructeur std :: cout << data.size() << std :: endl; fonctionne comme prévu; le programme se brise lorsque j'essaie d'insérer quelque chose dans la carte – mrs

+0

Cette "instanciation explicite" n'est pas une instanciation explicite. C'est la définition d'un membre de données statique appelé 'data' d'une spécialisation explicite du template' A' pour 'T = char'. Il n'y a pas de spécialisation explicite. Le compilateur doit émettre un message d'erreur pour ce code (si vous le commentez). –

1

Il y a plusieurs erreurs dans ce code. D'abord, l'idée initiale n'est pas bonne. Vous avez deux objets statiques globaux: a et A::data. L'ordre dans lequel ils sont initialisés est indéfini. Selon l'humeur de votre compilateur vous avez 50% de chances d'avoir le constructeur de a appelé en premier et tenté d'écrire quelque chose dans A::data non initialisé.

Ce problème est parfois appelé static init order fiasco. Une solution proposée est de transformer ces objets en objets statiques locaux en les déplaçant dans les fonctions:

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

objets statiques sont initialisés sur le premier appel à la fonction. A propos de la "instanciation explicite" a oublié template <>.

Mais après préfixer cette ligne avec template <> il est toujours pas définition mais une déclaration . Il déclare qu'il y a A :: data definition ailleurs. Pour le définir, vous devez l'initialiser avec quelque chose, voir Jack Lloyd répondre par exemple.

Questions connexes