2017-01-03 10 views
-2

Я пытаюсь создать класс, который хранит свои экземпляры в карте, как так:C++ Карта бросает вектор подстрочный из диапазона

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() с ошибкой векторного индекса вне диапазона. Я пробовал оглядываться, но я не могу найти какое-либо решение, касающееся карт и ошибки вне диапазона. Мое лучшее предположение из некоторых исследований, которые я сделал, это то, что это что-то о инициализации статического порядка, но я действительно не слишком уверен.

+0

1-я строка, которую вы имели в виду 'auto it = allApples.find (name);'? Я не вижу ничего подходящего для оператора std :: vector или index. – songyuanyao

+0

@songyuanyao, Да, эта строка является тем, что выбрасывает утверждение/исключение отладки (в сборке выпуска). Я не вижу ничего связанного с вектором, поэтому я так смущен. –

+0

Можете ли вы дать нам достаточно кода, чтобы мы могли скомпилировать его и воспроизвести проблему? –

ответ

1

Используйте статический объект функции-scope.

... 
private: 
    std::unordered_map<std::string, Apple*>& allApples() { 
     static std::unordered_map<std::string, Apple*> apples; 
     return apples; 
    } 

Это один из стандартных способов борьбы с фиаско порядка статического инициализации. Он работает, потому что статический объект с блочной областью гарантированно инициализируется, когда блок выполняется в первый раз.

Этот метод не будет работать, если между объектами, управляемыми таким образом, существуют взаимные зависимости.

+1

Это хорошее предложение, но в качестве ответа было бы намного лучше, если бы вы объяснили, почему это было бы лучше. –

0

Прежде всего, ваш метод 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"); 
+0

У меня есть свой код, я должен, вероятно, изменить его здесь, я просто не думал, что это имеет отношение к вопросу. –

+0

@ThomasPaine Без достаточного кода для репликации проблемы никто не может сказать, что уместно или нет. –

0

Вы получаете доступ allApples, прежде чем он был инициализирован. Пока вы не введете main, нет никакой гарантии, что был построен allApples, поэтому доступ к нему определенно не-нет.

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

+0

Но когда я распечатываю размер 'allApples' прямо перед точкой останова, он дает мне ноль, а это значит, что' allApples' инициализирован, правильно? Если 'allApples' не был инициализирован, не было бы это неопределенным поведением? –

+0

@ThomasPaine Это еще одна ошибка в коде. Вы не должны называть 'size', пока' allApples' не будет инициализирован, поскольку это UB. Вы попадаете в нуль, что вводит вас в заблуждение. Вот почему вы не должны этого делать! –

+0

Вот почему вы должны сделать как можно меньше в конструкторах и деструкторах - очень сложно контролировать контекст, в котором они выполняются. Наличие этого большого кода, вызванного всем конструктором глобального статического элемента, является орехом. Как вы можете сохранить этот код, не накладывая на него больших предупреждений, говоря «НЕ ДЕЛАЙТЕ НИЧЕГО НЕ ЮРИДИЧЕСКОГО, ЧТОБЫ ДОЛЖНО БЫТЬ ГЛАВНЫМ», и распространяйте его через все вызываемые функции? Псих. –