2009-10-05 4 views
1

J'ai les suivantes:problème avec std :: multimap

enum Type 
{ One = 0, Two}; 

class MySubClass 
{ 
private: 
MySubClass(); // prohibited 
MySubClass(const MySubClass&); // prohibited 
MySubClass & operator (const MySubClass&); // prohibited 
public : 
MySubClass(int x); 
}; 

class MyClass 
{ 
MyClass(int x) : m_x(new SubClass(x)) 
{} 
~MyClass() 
{ delete m_x; } 
private : 
MySubClass * m_x; 
}; 

typedef multimap<Type, MyClass> my_multimap; 
typedef pair<Type, MyClass> my_pair; 

Je suis en train de faire ce qui suit:

my_multimap my_map; 
my_map.insert(my_pair(One, MyClass(5))); 

Et je reçois un résultat d'exception non gérée, la l'application essaye de lire 0xfeeefeee etc.

Que se passe-t-il? Comment puis-je réparer cela? S'il vous plaît noter que ceci est un cas simplifié de ce que j'ai affaire;

+1

Vous n'avez pas besoin d '«interdire» le constructeur par défaut, car fournir un constructeur écrit à la main empêche efficacement le compilateur de générer un constructeur par défaut. Ce faisant, vous vous exposez à utiliser réellement le constructeur par défaut (de votre classe ou de vos amis) lorsqu'il n'y a pas d'implémentation derrière. –

Répondre

4

MyClass Aucun constructeur de copie n'a été défini. Cependant, std::pair devra utiliser le constructeur de copie pour MyClass. On suppose qu'il utilise le constructeur de copie par défaut de MyClass, ce qui donnera des copies aux objets construits du pointeur m_x. Et quand ils seront détruits, vous serez confrontés à plusieurs suppressions.

1

Vous devez écrire un constructeur de copie.

Ce qui se passe, c'est que MyClass est copié par la valeur le pointeur est partagé entre les copies. Désormais, lorsque les objets sont détruits, le pointeur est supprimé plusieurs fois.

Comme ceci:

class MyClass 
{ 
MyClass(int x) : m_x(new SubClass(x)) {} 
MyClass(const MyClass& myclass) : m_x(new SubClass(*myclass.m_x)) {} 
~MyClass() { delete m_x; } 
private : 
MySubClass * m_x; 
}; 

Il est évident que SubClass a besoin d'un constructeur de copie, aussi.

+0

Même s'il ne peut pas être utilisé dans le code affiché, il manque toujours un opérateur d'affectation. De plus, les classes dérivées n'auraient pas besoin d'un constructeur de copie défini, le compilateur serait bien. – sbi

5

Il existe une règle de base, appelée "Rule of Three": Chaque fois que vous avez un destructeur ou un opérateur d'affectation ou un constructeur de copie, il est très probable que vous en aurez besoin tous les trois. Votre code ne fait pas exception à cette règle. Pensez à ce qui se passe lorsque des objets de votre type sont copiés. Ce

MyClass obj1; 
MyClass obj2(obj1); 

se bloque également.

1

Comme tout le monde l'a mentionné, les classes ont besoin d'un constructeur de copie de travail pour pouvoir être stockées dans n'importe quel conteneur standard. Cependant, dans ce cas MySubClass désactive la copie. Cela vous laisse deux options:

1) MyClass doit également être non-copiable, auquel cas vous devrez stocker des pointeurs (intelligents) dans le multimap.

2) Les instances MyClass copiées doivent partager l'instance MySubClass. Pour implémenter ceci, le plus simple est de remplacer l'élément de pointeur par boost::shared_ptr<MySubClass> ou std::tr1::shared_ptr<MySubClass>. Cela vous libère de la tâche d'implémentation d'un destructeur, d'un constructeur de copie et d'un opérateur d'affectation.

Questions connexes