Ceci est une simplification d'un problème que j'ai rencontré dans un autre projet.Indice en dehors de la plage lors de la suppression d'un élément de l'ensemble
Dire que j'ai la classe suivante:
class MyClass {
public:
MyClass() {
std::cout << "MyClass constructed\n";
Instances().insert(this);
}
~MyClass() {
std::cout << "MyClass destructed\n";
Instances().erase(this);
}
static std::unordered_set<MyClass*>& Instances() {
static std::unordered_set<MyClass*> _instances;
return _instances;
}
};
Il a une unordered_set
statique qu'il utilise pour garder la trace des instances existantes de la classe. Lorsqu'une instance est construite, son adresse est ajoutée à l'ensemble; Lorsqu'une instance est détruite, son adresse est supprimée de l'ensemble.
Maintenant, j'ai une autre classe qui a une vector
de shared_ptr
s contenant des instances de MyClass
:
struct InstanceContainer {
std::vector<std::shared_ptr<MyClass>> instances;
};
Un point clé ici est qu'il ya une instance globale de cette classe au-dessus main
. Cela semble être une partie du problème, car déclarer la classe à l'intérieur de main
ne produit pas le problème.
intérieur de main
, je fais ce qui suit (par exemple l'instance mondiale de InstanceContainer
est appelé container
):
container.instances.emplace_back(std::shared_ptr<MyClass>(new MyClass));
Tout va bien jusqu'à ce que le programme se termine, quand je reçois une violation d'accès de lecture ("vecteur indice hors plage ") lorsque Instances().erase(this)
est exécuté dans le destructeur MyClass
.
Je pensais que peut-être j'essayais d'effacer l'instance de _instances
plusieurs fois (d'où le cout
s) - Cependant, le contructor est seulement appelé une fois, et le destructeur est appelé seulement une fois, comme on s'y attendrait. J'ai trouvé que lorsque cela se produit, _instances.size()
est égal à 0
. La chose étrange est, il est égal à 0
avant tous les appels à erase
. Avant que quelque chose ne soit effacé de l'ensemble, c'est vide ?! Ma théorie à ce stade est que cela a à voir avec l'ordre dans lequel les objets sont détruits à la fin du programme. Peut-être que le _instances
statique est en train d'être libéré avant que le destructeur MyClass
ne soit appelé.
J'espérais que quelqu'un serait en mesure de faire la lumière sur ce sujet, et confirmer si c'est ce qui se passe.
Ma solution de contournement consiste maintenant à vérifier si _instances.size()
est 0
avant d'essayer d'effacer. Est-ce sûr? Si non, que puis-je faire d'autre?
Si c'est important, j'utilise MSVC. Voici un executable example.