C++ Map выбрасывает векторный индекс за пределы диапазона
Я пытаюсь создать класс, который хранит свои экземпляры на карте следующим образом:
class Apple {
public:
static Apple* getApple(const std::string &name) {
auto it = allApples.find(name);
if (it == allApples.end()) // if this apple doesnt exist, make a new one
return new Apple(name);
else // if the apple exists, return its pointer
return it->second;
}
private:
static std::unordered_map<std::string, Apple*> allApples =
std::unordered_map<std::string, Apple*>();
Apple(const std::string &name) {
// create an apple
allApples.insert({ name, this });
}
}
Теперь я сделал классы, которые хранят статические яблоки, примерно так:
class Orange {
static Apple *myOrangeApple;
}
myOrangeApple = Apple::getApple("orange");
Когда я запускаю программу, она падает в первой строке метода getApple() с ошибкой векторного индекса вне диапазона. Я попытался осмотреться, но я не могу найти никакого решения, связанного с картами и ошибкой вне диапазона. Мой лучший вывод из некоторых исследований, которые я провел, заключается в том, что речь идет о инициализации статического порядка, но я действительно не слишком уверен.
3 ответа
Используйте статический объект области действия.
...
private:
std::unordered_map<std::string, Apple*>& allApples() {
static std::unordered_map<std::string, Apple*> apples;
return apples;
}
Это один из стандартных способов побороть статический порядок инициализации. Это работает, потому что статический объект области блока гарантированно будет инициализирован, когда блок выполняется в первый раз.
Этот метод не будет работать, если существуют взаимозависимости между объектами, управляемыми таким образом.
Прежде всего, ваш метод getApple должен быть статическим, и вы должны инициализировать член класса (статический член) вне класса. Попробуй это -
class Apple {
public:
static Apple* getApple(const std::string &name) {
auto it = allApples.find(name);
if (it == allApples.end()) // if this apple doesnt exist, make a new one
return new Apple(name);
else // if the apple exists, return its pointer
return it->second;
}
private:
static std::unordered_map<std::string, Apple*> allApples;
Apple(const std::string &name) {
// create an apple
allApples.insert({ name, this });
}
};
std::unordered_map<std::string, Apple*> Apple::allApples = std::unordered_map<std::string, Apple*>();
class Orange {
static Apple *myOrangeApple;
};
Apple * Orange::myOrangeApple=Apple::getApple("orange");
Вы получаете доступ allApples
прежде чем он был инициализирован. Пока вы не войдете main
нет никаких гарантий, что allApples
был построен, поэтому доступ к нему определенно нет-нет.
Иметь классы, которые добавляют себя в контейнеры, - плохая идея, но делать это в глобальном объекте действительно ужасно. Не делай этого.