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 был построен, поэтому доступ к нему определенно нет-нет.

Иметь классы, которые добавляют себя в контейнеры, - плохая идея, но делать это в глобальном объекте действительно ужасно. Не делай этого.

Другие вопросы по тегам