這是我在另一個項目中遇到的問題的簡化。從集合中刪除元素時,下標超出範圍
說我有下面的類:
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;
}
};
它有它使用跟蹤之類的現有實例的靜態unordered_set
。當一個實例被構造時,它的地址被添加到集合中;當一個實例被銷燬時,它的地址將從集合中刪除。
現在,我有了包含MyClass
實例shared_ptr
的vector
是另一個類:
struct InstanceContainer {
std::vector<std::shared_ptr<MyClass>> instances;
};
一個關鍵點在這裏是有這個類以上main
的全局實例。這似乎是問題的一部分,因爲在main
中聲明該類不會產生問題。
裏面的main
,我這樣做(說的InstanceContainer
全局實例被稱爲container
):
container.instances.emplace_back(std::shared_ptr<MyClass>(new MyClass));
一切都很好,直到節目結束,當我得到一個讀訪問衝突(「矢量標超出範圍「)Instances().erase(this)
在MyClass
的析構函數中執行。
我以爲也許我試圖從_instances
多次刪除實例(因此是cout
s) - 但是,構造函數只調用一次,並且析構函數只被調用一次,就像您期望的那樣。我發現當發生這種情況時,_instances.size()
等於0
。奇怪的是,在調用erase
之前,它等於0
。在任何東西被刪除之前,它是空的?!
我的理論在這一點上是與程序終止時對象被破壞的順序有關。也許在調用MyClass
的析構函數之前釋放靜態_instances
。
我希望有人能夠對此有所瞭解,並確認是否發生了這種情況。
我現在的解決方法是在試圖擦除之前檢查_instances.size()
是0
。這安全嗎?如果不是,我還能做什麼?
如果重要,我使用MSVC。這是一個executable example。