I've been struggling with this problem for about a week now. I don't know anymore what the problem is or if I update the iterator at the wrong place.
Let's get to the point. I'm trying to make a drop system where random items are being dropped from the monster after the player kills it. I get the items from the container below. After I receive the items from gear container, I want to delete received items from the gear vector as well. I.e. if "Plate armor" is dropped, I want to delete it from the gear container.
I have a vector of Gears where I register different gears such as weapon, armor or accessories. In our case, I will only focus on Armor.
std::vector<std::unique_ptr<Armor>> gear;
/* This is the simplified version of the vector.
I register different elements into my gear vector. Now is only armor focused on.
*/
gear.emplace_back(new Armor("Great pauldron", 25, 100));
gear.emplace_back(new Armor("Holy armor", 3, 18));
gear.emplace_back(new Armor("Dominic's eye", 18, 73));
gear.emplace_back(new Armor("Plate armor", 23, 21));
gear.emplace_back(new Armor("Poor armor", 57, 7));
gear.emplace_back(new Armor("Good shield", 91, 5));
gear.emplace_back(new Armor("Jodin's boots", 18, 66));
gear.emplace_back(new Armor("Ivona's gauntlets", 25, 100));
Next step, I make a class where I receive given the number of items as a vector of a vector iterator. (I use the public function for such operation.)
class Maker {
private:
template<typename Iter, typename RandomGen>
Iter randomSelection(Iter begin, Iter end, RandomGen& ran) {
std::uniform_int_distribution<> dist(0, std::distance(begin, end) - 1);
std::advance(begin, dist(ran));
return begin;
}
public:
template<typename Iter>
std::vector<Iter> randomSelection(Iter& begin, Iter& end, int amount) {
std::vector<Iter> it;
std::random_device randDev;
std::mt19937 gen(randDev());
for (int i = 0; i < amount; i++)
it.push_back(randomSelection<>(begin, end, gen));
return it;
}
};
Next, I make a vector of vector iterator to receive random items from the gear container.
Maker mak;
std::vector<std::vector<std::unique_ptr<Armor>>::iterator>& droppedItems =
mak.randomSelection(gear.begin(), gear.end(), 5);
The problem comes where I try to compare armor names from both vectors and if found; delete it from our very first gear vector. I almost always get an access violation error. It sometimes works to delete the items without producing any error. But just once every i.e. 20 tries.
for (auto& i = gear.begin(); i != gear.end();) {
for (auto& j = droppedItems.begin(); j != droppedItems.end(); j++) {
/* This if statement is where I get the access violation error; 0x05.*/
if (i->get()->getName() == (*j)->get()->getName()) {
std::cout << std::endl << i->get()->getName() << " has been deleted!\n";
i = gear.erase(i);
}
else
i++;
}
}
I assume I increment the iterator(s) at the wrong place. I assume I perform the erase operation finely but I'm literally out of ideas.
std::vector<std::vector<std::unique_ptr<Armor>>::iterator>& droppedItemsis a reference to a temporary? Other than that, you're probably invalidating the rest of the iterators you hold when yougear.erase(i).imay reach::end()and you are trying to dereference it in your if statement... One possibilty would be to check (after calling erase)if(i == gear.end()) break;(and stop the loop)iiterator after it reaches::end()?gear, that needs to be the inner loopif(i == gear.end()) break;(and stop the loop) or swap the inner with the outer loop