c++ - Compare different vector iterators and erase element from the first vector -
i've been struggling problem week now. don't know anymore problem or if update iterator @ wrong place.
let's point. i'm trying make drop system random items being dropped monster after player kills it. items container below. after receive items gear container, want delete received items gear vector well. i.e. if "plate armor" dropped, want delete gear container.
i have vector of gears register different gears such weapon, armor or accessories. in our case, focus on armor.
std::vector<std::unique_ptr<armor>> gear; /* simplified version of vector. register different elements gear vector. 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, make class receive given number of items vector of vector iterator. (i use public function 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()); (int = 0; < amount; i++) it.push_back(randomselection<>(begin, end, gen)); return it; } }; next, make vector of vector iterator receive random items gear container.
maker mak; std::vector<std::vector<std::unique_ptr<armor>>::iterator>& droppeditems = mak.randomselection(gear.begin(), gear.end(), 5); the problem comes try compare armor names both vectors , if found; delete our first gear vector. access violation error. works delete items without producing error. once every i.e. 20 tries.
for (auto& = gear.begin(); != gear.end();) { (auto& j = droppeditems.begin(); j != droppeditems.end(); j++) { /* if statement access violation error; 0x05.*/ if (i->get()->getname() == (*j)->get()->getname()) { std::cout << std::endl << i->get()->getname() << " has been deleted!\n"; = gear.erase(i); } else i++; } } i assume increment iterator(s) @ wrong place. assume perform erase operation finely i'm literally out of ideas.
std::vector<t>::erase(iter) invalidates iterators , references @ or after iter (including end()), still attempt use these invalidated iterators droppeditems container afterwards.
for example, if lets droppeditems contains iterator pointing last element of gears, , other iterators. when erase other element of gears, invalidates iterator last element. when call gears.erase() passing (invalidated) iterator last element, cause undefined behavior.
std::vector<int> test{1,2,3,4}; auto firstiter = test.begin(); auto seconditer = firstiter + 1; auto thirditer = seconditer + 1; auto fourthiter = thirditer + 1; test.erase(seconditer); // invalidates seconditer, thirditer , fourthiter // not firstiter you can think of std::vector<t> iterators pointers t. if erase element, elements following moved in memory keep vector elements dynamic array. hence iterators "pointing" elements not continue point @ correct elements.
before test.erase(seconditer):
address: | 0x0 | 0x1 | 0x2 | 0x3 | value: | 1 | 2 | 3 | 4 | firstiter = 0x0 // points element value 1 seconditer = 0x1 // points element value 2 thirditer = 0x2 // points element value 3 fourthiter = 0x3 // points element value 4 after test.erase(seconditer):
address: | 0x0 | 0x1 | 0x2 | value: | 1 | 3 | 4 | firstiter = 0x0 // still points element value 1 seconditer = 0x1 // no longer points element value 2 thirditer = 0x2 // no longer points element value 3 fourthiter = 0x3 // out of vector bounds i suggest instead set random elements of gears nullptr , compact vector afterwards:
template <typename t> void freerandomitems(std::vector<std::unique_ptr<t> > & vec, std::size_t amount) { if (amount == 0u) return; // nothing // setup rng: std::random_device randdev; std::mt19937 gen(randdev()); if (amount == 1u) { // remove 1 random element: vec.erase(randomselection(vec.begin(), vec.end(), gen)); return; } // deallocate amount pointed elements in vector, reset pointers: { randomselection<>(vec.begin(), vec.end(), gen)->reset(); } while (--amount); // remove nullptr elements vec: vec.erase( std::remove_if( vec.begin(), vec.end(), [](std::unique_ptr<t> const & v) noexcept { return !v; }), vec.end()); }
Comments
Post a Comment