Ошибка массива C SFML: местоположение чтения с нарушением доступа 0xC0000005

#c #sfml

#c #sfml

Вопрос:

Я создаю игру на C и SFML, и у меня возникла проблема при рендеринге различных элементов с помощью массива. Когда я пытаюсь нарисовать массив спрайтов, отладка проходит нормально, предупреждений и ошибок нет, но моя игровая программа работает всего 20 секунд, затем она останавливается и сообщает: «Необработанное исключение в 0x7C50CF2E (sfml-graphics-d-2.dll ), ECOVID-19 SFML.exe ): 0xC0000005: местоположение чтения с нарушением доступа 0xCCCCCCD0.’ Я сделал все, что мог, но я не знаю, почему возникает это исключение. Вот мои коды, которые, как я подозреваю, являются причиной ошибки. Спасибо за чтение, несмотря на мой плохой английский.

  #include <SFML/Graphics.hpp>
 ...
 using namespace std;
 using namespace sf;
 ...

 int main () {
 ...

 //item Sprites

 Texture bombTex;
 bombTex.loadFromFile("images/bomb.png");
 Sprite bomb;
 ...
 Texture bomb2Tex;
 bomb2Tex.loadFromFile("images/bomb_2.png");
 Sprite bomb_2;
 ...
 Texture cakeTex;
 cakeTex.loadFromFile("images/cake.png");
 Sprite cake;
 ...
 Texture coffeeTex;
 coffeeTex.loadFromFile("images/coffee.png");
 Sprite coffee;
 ...
 Texture chickenTex;
 chickenTex.loadFromFile("images/chicken.png");
 Sprite chicken;
 ...
 Texture pizzaTex;
 pizzaTex.loadFromFile("images/pizza.png");
 Sprite pizza;

 //item array (I made an item array to display amp; render various items in the game screen.)
 Sprite item[10]; //Although I change the array size to 4 or 5, the same exception occurs.
 item[0] = bomb;
 item[1] = coffee;
 item[2] = bomb_2;
 item[3] = chicken;
 item[4] = pizza;

 std::vector<Sprite> items;
 items.push_back(Sprite(item[4]));

 ...

 while (window.isOpen())
 {   ...
     ...
  for (size_t i = 0; i < items.size(); i  )
  {
     if (humanArr[index].getGlobalBounds().intersects(item[i].getGlobalBounds())) 
     //humanArr[index] is a player Sprite.
      {
         ...
          items.erase(items.begin()   i);
       }
   }
   ...
  window.clear();
   ...
  for (size_t i = 0; i < items.size(); i  )
     {
         window.draw(item[i]); // <- the exception error occurs here.
      }

   ...
 window.display();
  }
 return 0;
}
  

Комментарии:

1. std::vector<Sprite> items; Sprite Имеет правильную семантику копирования? Если нет, то наличие vector of Sprite не будет работать слишком хорошо.

2. Увеличивается ли вектор items со временем? Если это так, то в цикле вы говорите, что .intersects(item[i].getGlobalBounds()) если items размер больше item , то вы получаете доступ из диапазона

3. Пропущено много кода, поэтому трудно сказать. Все ли Texture s все еще находятся в области видимости, когда вы draw создаете спрайты?

4. Кажется возможным, что причиной является некоторое несоответствие между items и item . Ваш цикл рисования предполагает, что он item по крайней мере такой же большой, как items но, возможно, это не так. Просто иметь две параллельные структуры данных, подобные этой, немного сомнительно.

Ответ №1:

Что может происходить, так это то, что при копировании Sprite item[10]; в std::vector<Sprite> items; класс Sprite создает неглубокую копию. Это означает, что если класс Sprite выделяет какую-либо память с помощью new оператора и сохраняет ее в указателе на член, то поверхностная копия скопирует только адрес, на который указывает указатель. При выполнении вызова items.erase(items.begin() i); будет вызван деструктор спрайта, и в деструкторе это может быть вызов delete в этом указателе на некоторый ресурс.

При вызове window.draw(item[i]); библиотека попытается использовать этот ресурс и обнаружит недопустимый адрес.

Я предлагаю, чтобы вы не использовали Sprite item[10]; и только std::vector<Sprite> items; , вот так:

 std::vector<Sprite> items;

items.push_back(bomb);
items.push_back(coffee);
...
window.draw(items[i]);
  

Вам не нужно использовать промежуточный массив, просто std::vector<Sprite> ;