I am struggling with removing a unique_ptr from vector. I have a vector:
std::vector<std::unique_ptr<Agent>>;
which I am filling with certain number of Agents. I do it in the following way:
In class constructor list:
agentsVec(std::accumulate(agentsQuantity.begin(), agentsQuantity.end(), 0,
[](int value, const QuantityMap::value_type& p) { return value + p.second; }))
And in a function responsible for generating agents:
auto agentVecIter = agentsVec.begin();
std::for_each(agentsQuantity.begin(), agentsQuantity.end(), [this, &agentVecIter](const QuantityMap::value_type& p)
{
std::generate_n(agentVecIter, p.second, [this, &p]()
{
auto agent = factory.createAgent(p.first);
changeAgentOnLattice(generatePosition(), agent->getID());
return agent;
});
std::advance(agentVecIter, p.second);
});
agentsQuantity is a map which denotes number of agents of certain type. Agent factory returns std::unique_ptr;
During the program there can be a need to delete some Agent from vector, based on it's ID (Agent's ID is then returned to freeID's stack).
Kill agent:
std::experimental::erase_if(agentsVec, [this, &positionID](auto const& agent) {
auto agentID = agent->getID();
if (positionID == agentID) {
Utils::addIDToStack(agentID);
return true;
}
return false;
});
To test that, I added 5 agents which will be "killed". In about 40% of cases I got:
Debug Assertion Failed! Vector iterator not dereferencable
What am I doing wrong?
EDIT: More code for clarification. Lattice of agents (which contains agentsVec) is created in Environment class. Environment then step into infinite loop and iterates through all positions in lattice and check if something exists there. If yes -> it moves the agent and updates its health:
Environment::Health update:
for (int i = 0; i < latticeSize; i++) {
for (int j = 0; j < latticeSize; j++) {
if (lattice->getAgentID(Position(i, j))) {
Agent* currentAgent = lattice->getAgentInstance(Position(i, j));
currentAgent->updateHealth();
if (currentAgent->getAgentType() == Enums::AgentType::Predator && currentAgent->getHealth() <= -10) {
lattice->killAgent(Position(i, j));
}
}
}
}
Lattice::Move agent:
const auto originRow = Utils::BoundaryCondition(origin.first, latticeSize);
const auto originCol = Utils::BoundaryCondition(origin.second, latticeSize);
const auto destRow = Utils::BoundaryCondition(destination.first, latticeSize);
const auto destCol = Utils::BoundaryCondition(destination.second, latticeSize);
if (getAgentID(origin) == static_cast<int>(Enums::AgentType::Field)) {
Logger::getInstance().Log("lattice", "\tCannot move - there is no moving creature on origin position");
return false;
}
if (getAgentID(destination) != static_cast<int>(Enums::AgentType::Field)) {
Logger::getInstance().Log("lattice", "\tCannot move - destination position is occupied");
return false;
}
latticeMap[destRow][destCol] = static_cast<int>(getAgentID(origin));
latticeMap[originRow][originCol] = static_cast<int>(Enums::AgentType::Field);
Logger::getInstance().Log("lattice", "\tMoved succesfully");
return true;
Agent getter (used in Environment to get Agent pointer from Lattice::agentsVec)
Agent* Lattice::getAgentInstance(Position position) {
int ID = getAgentID(position);
auto it = std::find_if(std::execution::par, agentsVec.begin(), agentsVec.end(),
[=](std::unique_ptr<Agent>& agent) { return agent->getID() == ID; });
if (it != agentsVec.end()) {
return it->get();
}
return nullptr;
}
And AgentType getter:
Enums::AgentType Lattice::checkAgentType(int ID)
{
auto it = std::find_if(std::execution::par, agentsVec.begin(), agentsVec.end(),
[=](std::unique_ptr<Agent>& agent) { return agent->getID() == ID; });
if(it != agentsVec.end()) {
return it->get()->getAgentType();
}
return Enums::AgentType::Unknown;
}