List Iterator not Dereferenceable Run time - c++

portalManager::portalManager(SDL_Renderer* argRenderer)
{
mLootManager = new lootManager();
mLootManager->initialize();
lootPortal* newPortal;
newPortal = new lootPortal(128, 128, Portal::eForest, Tile::eForest);
mPortalList.push_back(newPortal);
newPortal = new lootPortal(256, 256, Portal::eForest, Tile::eForest);
mPortalList.push_back(newPortal);
mPortalSheet = new spriteSheet(192, 192, 0);
mPortalSheet->loadTexture("Images/Portals.png", argRenderer);
mRenderQuad.w = Tile::cTileSize;
mRenderQuad.h = Tile::cTileSize;
mTextureQuad.w = Tile::cTileSize;
mTextureQuad.h = Tile::cTileSize;
}
void portalManager::render(int argX, int argY, int argW, int argH, SDL_Renderer* argRenderer)
{
std::list<lootPortal*>::const_iterator itr = mPortalList.begin();
for (itr = mPortalList.begin(); itr != mPortalList.end(); itr++);
{
std::cout<<(*itr)->getX()<<std::endl;
mRenderQuad.x = (*itr)->getX();
mRenderQuad.y = (*itr)->getY();
if ((mRenderQuad.x >= argX && mRenderQuad.x <= argX+argW) && (mRenderQuad.y >= argY && mRenderQuad.y <= argY + argH))
{
mTextureQuad.x = 0;
mTextureQuad.y = 0;
}
}
};
The problem happens in the for loop of render when I try to dereference the iterator.
I have checked that the list is not empty I can access the first and last element of the list but for some reason the for loop always throws a list Iterator not dereferenceable.

The problem is in this line:
for (itr = mPortalList.begin(); itr != mPortalList.end(); itr++);
^
You have a spurious semi-colon at the end of the for clause. Easy fix - get rid of it.
If you're curious as to why this causes a problem - what this means is that the entire loop will complete before it proceeds to execute the code in the body of the loop (because that code isn't actually in the body of the loop after all). And once it gets to that code, itr equals mPortalList.end().

Related

How can I optimize Astar for vast empty spaces?

I am creating a game with a 3D grid for flying entities, So I have a lot of points and connections in the air where there aren't any obstructions. I didn't want to decrease the resolution of my grid so I thought I could just skip over chunks (or empties as I call them) of the Astar map while they're not containing any obstructions, and I modified Godot's Astar algorithm to do this.
Unfortunately this ended up being slower than looping through points one at a time due to the way I implemented this modification, which needs to loop through all the edge points of an empty.
2D representation of how one edge point of an empty connects to all other edge points:
This ends up looping through a larger number of points than letting the A* algorithm work it's way through the empty.
So I'm sorta stumped on how to make this more efficient while still preserving the most optimal path.
I could potentially narrow down what faces of the empty should be scanned over by first comparing the center points of all 8 faces of the empty (as my grid consists of hexagonal prisms). Or maybe I should somehow use the face center points of the empty's faces exclusively instead of all edge points.
I mainly want to know if anyone has worked on an issue like this before, and if so what would be the recommended solution?
Here is the astar loop for reference:
bool AStar::_solve(Point *begin_point, Point *end_point, int relevant_layers) {
pass++;
//make sure parallel layers are supported
// or if *relevant_layers is 0 then use all points
bool supported = relevant_layers == 0 || (relevant_layers & end_point->parallel_support_layers) > 0;
if (!end_point->enabled || !supported) {
return false;
}
bool found_route = false;
Vector<Point *> open_list;
SortArray<Point *, SortPoints> sorter;
begin_point->g_score = 0;
begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
open_list.push_back(begin_point);
while (!open_list.empty()) {
Point *p = open_list[0]; // The currently processed point
if (p == end_point) {
found_route = true;
break;
}
sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list
open_list.remove(open_list.size() - 1);
p->closed_pass = pass; // Mark the point as closed
//if the point is part of an empty, look through all of the edge points of said empty (as to skip over any points within the empty).
OAHashMap<int, Point*> connections;
PoolVector<Empty*> enabled_empties;
int size = p->empties.size();
PoolVector<Empty*>::Read r = p->empties.read();
for (int i = 0; i < size; i++) {
Empty* e = r[i];
supported = relevant_layers == 0 || (relevant_layers & e->parallel_support_layers) > 0;
//if the empty is enabled and the end point is not within the empty
if (e->enabled && supported && !end_point->empties.has(e)) {
enabled_empties.append(e);
//can travel to any edge point
for (OAHashMap<int, Point*>::Iterator it = e->edge_points.iter(); it.valid; it = e->edge_points.next_iter(it)) {
int id = *it.key;
Point* ep = *(it.value);
ep->is_neighbour = false;
//don't connect to the same point
if (id != p->id && (i == 0 || !connections.has(id))) {
connections.set(id, ep);
}
}
}
}
//add neighbours to connections
for (OAHashMap<int, Point*>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
int id = *it.key;
Point* np = *(it.value);// The neighbour point
np->is_neighbour = true;
//don't need to check for duplicate point connections if no empties
if (size == 0 || !connections.has(id)) {
//don't add points within enabled empties since they're meant to be skipped over
if (np->empties.size() > 0 && !np->on_empty_edge) {
bool in_enabled_empty = false;
PoolVector<Empty*>::Read r1 = np->empties.read();
for (int i = 0; i < np->empties.size(); i++) {
if (enabled_empties.has(r1[i])) {
in_enabled_empty = true;
break;
}
}
if (!in_enabled_empty) {
connections.set(id, np);
}
}
else {
connections.set(id, np);
}
}
}
for (OAHashMap<int, Point *>::Iterator it = connections.iter(); it.valid; it = connections.next_iter(it)) {
Point *e = *(it.value); // The neighbour point
//make sure parallel layers are supported
// or if *relevant_layers is 0 then use all points
supported = relevant_layers == 0 || (relevant_layers & e->parallel_support_layers) > 0;
if (!e->enabled || e->closed_pass == pass || !supported) {
continue;
}
real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * e->weight_scale;
bool new_point = false;
if (e->open_pass != pass) { // The point wasn't inside the open list.
e->open_pass = pass;
open_list.push_back(e);
new_point = true;
} else if (tentative_g_score >= e->g_score) { // The new path is worse than the previous.
continue;
}
e->prev_point = p;
e->prev_point_connected = e->is_neighbour;
e->g_score = tentative_g_score;
e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
if (new_point) { // The position of the new points is already known.
sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw());
} else {
sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw());
}
}
}
return found_route;
}
Note: I'm still not exactly sure what the sorter does.
the entire code can be seen here in a_star.cpp and a_star.h
Edit:
if anyone wants to reference or use this, I've modified the Astar code to add user-defined octants and to use a user-defined straight line function (they are user-defined so they can work with any type of grid) to be used between octants when possible to further decrease runtime, and it works very well in terms of speed. Though the pathing is not optimal, especially when adding a lot of obstacles/restricting the available positions.

Why does this function get wrong argument from iterator?

I'm writing a Space Invaders clone for IT project on uni. All the methods work, but I have a problem with deleting enemies.
I redone my code to use iterators. I store enemies in vector(horizontal) of vectors(vertical) of Enemy. The code works fine until i shoot more than 2 projectiles at a time when it gives me an error.
if (projectiles.size() != 0)
{
for (auto itr_columns = enemies.begin(); itr_columns != enemies.end(); itr_columns++)
{
for (auto itr_rows = itr_columns->begin(); itr_rows != itr_columns->end();)
{
if (projectiles.size() == 0)
{
break;
}
for (auto itr_projectiles = projectiles.begin(); itr_projectiles != projectiles.end();)
{
if (itr_projectiles->Collision(*itr_rows))
{
itr_projectiles = projectiles.erase(itr_projectiles);
itr_rows = itr_columns->erase(itr_rows);
}
else
{
itr_rows++;
itr_projectiles++;
}
}
}
}
}
That's the error i get:
line: if (itr_projectiles->Collision(*itr_rows))
Expression: can't dereference out of range vector iterator
Look at the instruction :
itr_rows = itr_columns->erase(itr_rows);
By doing that, you invalidate the iterators of itr_columns while you're are in the loop, which does use these iterators.
Never call functions invalidating iterators when you a are in a loop.

Why don't the changes to my variables survive until the next iteration?

I want to update instances of a struct that I am storing in a map within a loop, but the changes to the instance variables don't survive the iterations of the loop (within one iteration, the new variables get properly set, in the next operation they are reset to their initial value).
Here is a simplified version of what I am doing:
map<int, RegionOverFrames>* foundRegions = new map<int, RegionOverFrames>;
for (int i = 0; i < frames.size(); i++) {
// find all regions in current frame
map<int, RegionOverFrames> regionsInCurrentFrame;
for (Region region: currentFrame.regions) {
if (foundRegions->count(region.regionId) == 0) {
RegionOverFrames foundRegion;
foundRegion.regionId = region.regionId;
regionsInCurrentFrame[region.regionId] = foundRegion;
(*foundRegions)[region.regionId] = foundRegion;
}
else if (foundRegions->count(region.regionId) > 0) {
RegionOverFrames foundRegion = (*foundRegions)[region.regionId];
regionsInCurrentFrame[region.regionId] = foundRegion;
}
}
// update found regions (either by adding weight or setting the end index)
for (auto it = foundRegions->begin(); it != foundRegions->end(); it++) {
RegionOverFrames foundRegion = it->second;
// the region that was found before is also present in this frame
if (regionsInCurrentFrame.count(foundRegion.regionId) > 0) {
float weight = currentFrame.getRegion(foundRegion.regionId).getWeight();
foundRegion.accumulatedWeight += weight; // this update of accumulatedWeight is not present in the next loop, the accumulatedWeight only gets assigned the value of weight here, but in the next iteration it's reset to 0
}
}
}
Could it have something to do with the fact that I am using an iterator it to access the objects within my map<int, RegionOverFrames>* foundRegions or with the fact that foundRegions is declared with a pointer and stored on the heap?
Note RegionOverFrames is a simple struct looking like this:
struct RegionOverFrames {
int regionId;
double accumulatedWeight;
}
Your issue is that you are creating a copy of the found region rather than updating the object found in the map.
RegionOverFrames foundRegion = it->second;
// ^ copy created
You should use references instead:
RegionOverFrames &foundRegion = it->second;
// ^ use reference

ConcurrentHashMap in JDK7 code explanation (scanAndLockForPut)

The source codes of the method scanAndLockForPut in ConcurrentHashMap in JDK7 says:
private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
HashEntry<K,V> first = entryForHash(this, hash);
HashEntry<K,V> e = first;
HashEntry<K,V> node = null;
int retries = -1; // negative while locating node
while (!tryLock()) {
HashEntry<K,V> f; // to recheck first below
if (retries < 0) {
if (e == null) {
if (node == null) // speculatively create node
node = new HashEntry<K,V>(hash, key, value, null);
retries = 0;
}
else if (key.equals(e.key))
retries = 0;
else
e = e.next;
}
else if (++retries > MAX_SCAN_RETRIES) {
lock();
break;
}
else if ((retries & 1) == 0 &&
(f = entryForHash(this, hash)) != first) {
e = first = f; // re-traverse if entry changed
retries = -1;
}
}
return node;
}
I understand what the codes mean, but what I don't is this else if entry:
else if ((retries & 1) == 0 && (f = entryForHash(this, hash)) != first)
My question is:
Why do we have to do "(retries & 1) == 0"?
EDIT:
I kind of figure it out. It's all because the constant MAX_SCAN_RETRIES:
static final int MAX_SCAN_RETRIES = Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
In single core processor, MAX_SCAN_RETRIES = 1. So the second time the thread steps into the loop "while(tryLock)", it doesn't have to check whether the first node was changed.
However, in multi cores processor, this will behave like checking whether the first node is changed every 2 times in the while loop.
Is the above explanation correct?
Let's break this down:
1:
(retries & 1) == 0
This returns 1 for odd numbers, 0 for even numbers. Basically, to get past, there's a 1 in 2 chance, if the number is even.
2:
f = entryForHash(this, hash)
f is a temporary variable used to store the value of the latest entry in the segment.
3:
(/* ... */) != first
Checks if the value changed. If it did, it would move the current entry to the start, and re-iterate the linked nodes again in attempt to acquire the lock.
I've asked this question on the concurrency-interest mailing list, and the author(Doug Lea) himself replied:
Yes. We need only ensure that staleness is eventually detected.
Alternating the head-checks works fine, and simplifies use of
the same code for both uni- and multi- processors.
link
So I think this is the end of this question.
I think there are some bugs for the method!
first let us see the put method:
final V put(K key, int hash, V value, boolean onlyIfAbsent) {
HashEntry<K,V> node = tryLock() ? null :
scanAndLockForPut(key, hash, value);//1. scanAndLockForPut only return
// null or a new Entry
V oldValue;
try {
HashEntry<K,V>[] tab = table;
int index = (tab.length - 1) & hash;
HashEntry<K,V> first = entryAt(tab, index);
for (HashEntry<K,V> e = first;;) {
if (e != null) {
K k;
if ((k = e.key) == key ||
(e.hash == hash && key.equals(k))) {
oldValue = e.value;
if (!onlyIfAbsent) {
e.value = value;
++modCount;
}
break;
}
e = e.next;
}
else {
// 2. here the node is null or a new Entry
// and the node.next is the origin head node
if (node != null)
node.setNext(first);
else
node = new HashEntry<K,V>(hash, key, value, first);
int c = count + 1;
if (c > threshold && tab.length < MAXIMUM_CAPACITY)
rehash(node);
else
setEntryAt(tab, index, node);//3. finally, the node become
// the new head,so eventually
// every thing we put will be
// the head of the entry list
// and it may appears two equals
// entry in the same entry list.
++modCount;
count = c;
oldValue = null;
break;
}
}
} finally {
unlock();
}
return oldValue;
}
step: 1. scanAndLockForPut only return null or a new Entry.
step: 2. the node eventualy a new Entry, and the node.next is the origin head node
step: 3. finally, the node become the new head,so eventually every thing we put will be the head of the entry list and it may appears two equals entry in the same entry list when the concurrentHashMap works in a concurrent environment.
That is my opinion, and I am not exactly sure about whether it is right or not. So I hope you all give me some advice,thanks a lot!!

strange iterator behavior in for loop in g++

I got this strange issue following is the code snippet which is working properly.
std::multimap<long,int>::iterator dateItr = reconnQueueDates.begin();
while( dateItr!=reconnQueueDates.end() ){
LOG_DEBUG("RUN comparision " <<cDateTime<< ", "<<dateItr->first);
if(dateItr->first <= cDateTime){
long nextTimeout = -1;
if( (nextTimeout = callReconnects(dateItr->second,dateItr->first))>-1){
if(nextTimeout>0){
reconnQueueDates.insert(std::pair<long , int>(nextTimeout, dateItr->second));
}
reconnQueueDates.erase(dateItr);
LOG_DEBUG("modified the iterator ressetting");
dateItr = reconnQueueDates.begin();
LOG_DEBUG("resset iter");
}//end of callreconnect if
}else{
++dateItr;
} //else for datetime check
}//end of while
Before this I was using a for loop with ++dateItr in the loop as follows
for( ;dateItr!=reconnQueueDates.end();++dateItr ){
LOG_DEBUG("RUN comparision " <<cDateTime<< ", "<<dateItr->first);
if(dateItr->first <= cDateTime){
long nextTimeout = -1;
if( (nextTimeout = callReconnects(dateItr->second,dateItr->first))>-1){
if(nextTimeout>0){
reconnQueueDates.insert(std::pair<long , int>(nextTimeout, dateItr->second));
}
reconnQueueDates.erase(dateItr);
LOG_DEBUG("modified the iterator ressetting");
dateItr = reconnQueueDates.begin();
LOG_DEBUG("resset iter");
}// callReconnect
} // check datetime
}// for loop
While debugging I found out that after changing the map inside the loop the iterator value inside the for construct was still using the old address.
I am using and ubuntu 12.04 with g++ version 4.6.3. Seems to me some kind of compiler bug or some kind of optimization doing this.
Any idea which flag or a bug it might be.
After reconnQueueDates.erase(dateItr); the iterator in dateItr is invalid and any use of it is undefined behaviour. Since both your old and your new for loop use it afterwards, the fact that your new version "works" is purely accidental.
The correct way to do it is to first extract all data you might still need (including the position of the next iterator) before erasing that element. For example:
std::multimap<long,int>::iterator dateItr = reconnQueueDates.begin();
while( dateItr!=reconnQueueDates.end() )
{
LOG_DEBUG("RUN comparision " <<cDateTime<< ", "<<dateItr->first);
if(dateItr->first <= cDateTime)
{
std::multimap<long,int>::iterator nextItr = dateItr;
++nextItr;
long nextTimeout = -1;
if( (nextTimeout = callReconnects(dateItr->second,dateItr->first))>-1)
{
std::pair<long , int> newentry = std::make_pair(nextTimeout, dateItr->second);
reconnQueueDates.erase(dateItr);
if(nextTimeout>0)
{
reconnQueueDates.insert(newentry);
}
LOG_DEBUG("modified the iterator resetting");
nextItr = reconnQueueDates.begin();
LOG_DEBUG("reset iter");
}//end of callreconnect if
dateItr = nextItr;
}
else
{
++dateItr;
} //else for datetime check
}//end of while