Iterator over a list pointing to wrong elements - c++

I have 2 variables: std::list lst; and std::list<A*>::iterator lstiter with A being a class. The lst is filled with pointers to the class! B is an other class that holds both variables.
Puts iterator at the begin of the list:
void B::iterstart() {
lstiter = lst.begin();
}
void B::iternext() {
iteratend();
lstiter = ++lstiter;
}
void B::iterprev() {
iteratstart();
lstiter = --lstiter;
}
void B::iteratend() {
if (lst.empty())
throw -1;
if (lstiter == lst.end())
throw "Error: end of list\n";
}
void B::iteratstart() {
if (lst.empty())
throw -1;
if (lstiter == lst.begin())
throw "Error: begin of list\n";
}
(I also have a function that gets the pointer at the element in the list the iterator is pointing too at the moment. Iteratend and iteratstart throw an exception when there are no elements in the list and when I try to go past the last or first element. This is where my problem is!
Now I call: iterstart(); iternext(); iternext(); iternext(); I never get the message!(End of list)
And I do have some other bugs too, Sometimes I call the procedure prev, but I get the return value of the procedure next! (But I want to try to solve the other problem first)

This lstiter = ++lstiter is wrong. With an integer it might work but when used with complicated C++ objects it does not always perform correctly because it depends on the specific implementation of the increment and copy functions. Also, why would you want to do it? All you need is ++lstiter.

Related

Doubly linked list C++ Delete element

I have problem with deleting first and last element of linked list. When I am trying to delete first element, my code do nothing (when I print a list, deleted element is still there). When I am trying to delete the last one, console shows core dumped.
Here is my code:
void Delete_element(point del, node *elem) {
struct node *temp = elem;
if(elem->p.x==del.x && elem->p.y == del.y) {
elem=elem->next;
return;
} else {
while(elem->next->next!=NULL) {
if(elem->next->p.x==del.x && elem->next->p.y==del.y) {
temp=elem->next;
elem->next=elem->next->next;
elem->prev=temp->prev;
return;
}
temp=temp->next;
}
}
if(elem->next->p.x==del.x && elem->next->p.y==del.y) {
elem->next=NULL;
}
}
EDIT: After fixes
void Delete_element(point del, node *& elem){
struct node *temp = elem;
if(elem->p.x==del.x && elem->p.y == del.y){
temp = elem->next;
free(elem);
elem=temp;
return;
}else{
while(elem->next->next!=NULL)
{
if(elem->next->p.x==del.x && elem->next->p.y==del.y)
{
temp=elem->next;
elem->next=elem->next->next;
elem->next->prev=elem;
return;
}
elem=elem->next;
}}
if(elem->next->p.x==del.x && elem->next->p.y==del.y){
elem->next=NULL;
return;
}
}
Now removing an middle element is broken.
Please help
Firstly, you are not actually deleting anything. You are, however, leaving dangling pointers which result in a memory leak. In each case you should be deleting something. This is why you still see the data instead of garbage or some kind of crash.
Second, you look to have an infinite loop. When you hit your while loop you never change elem so elem->next->next never changes.
Third, why are you deleting elem->next in your while loop? Delete elem to avoid confusion.
EDIT:
You can't change elem like that. Think of elem like an integer or float you pass in. If you want elem to maintain the head change you're going to have to pass in a pointer to elem which ends up being a pointer to a pointer.
I believe you have at least two bugs:
In order to modify the first element you must pass a reference to the first pointer as you intent to modify this pointer. use:
void Delete_element(point del, node *& elem)
Removing an element from the middle seems to be broken.
instead of:
elem->prev=temp->prev
you should have:
elem->next->prev=element

How do I delete an object pointer from a vector without causing a memory error?

I have a vector of object pointers that I am adding to and deleting from while looping through to update objects. I can't seem to delete objects that have "died" from the vector without causing a memory error. I'm not really sure what I'm doing wrong. Listed below is my update method and it's sub method.
void Engine::update(string command){
if(getGameOver()==false){
for(p=objects.begin();p!=objects.end();p++){
spawnUpdate(command);
//cout<<"Spawn"<<endl;
objectUpdate(command);
//cout<<"object"<<endl;
scrollUpdate(command);
// cout<<"scroll"<<endl;
killUpdate(command);
//cout<<"kill"<<endl;
}
}
}
void Engine::killUpdate(std::string command){
if((*p)->getIsDead()==true){delete *p;}
}
void Engine::objectUpdate(string command){
(*p)->update(command,getNumObjects(),getObjects());
if(((*p)->getType() == PLAYER)&&((*p)->getPosX()>=getFinishLine())){setGameOver(true);}
}
void Engine::scrollUpdate(string command){
//Check player position relative to finishLine
if(((*p)->getType() == PLAYER)&&((*p)->getPosX()>(SCREEN_WIDTH/2))){
(*p)->setPosX((*p)->getPosX()-RUN_SPEED);
setFinishLine(getFinishLine()-RUN_SPEED);
for(q=objects.begin();q!=objects.end();q++){
//Shift objects to pan the screen
if((*q)->getType() == OPPONENT){(*q)->setPosX((*q)->getPosX()-RUN_SPEED);}
if((*q)->getType() == BLOCK){(*q)->setPosX((*q)->getPosX()-RUN_SPEED);}
}
}
}
void Engine::spawnUpdate(string command){
if(command.compare("shoot")==0){
cout<<"Bang!"<<endl;
if((*p)->getType() == PLAYER){objects.push_back(new Bullet((*p)->getPosX(),(*p)->getPosY(),(*p)->getState()));cout<<"Bullet success "<<endl;}
}
}
Some assumptions/definitions:
objects a member variable, something like vector<Object*> objects;
p is also a member variable, something like vector<Object*>::iterator p;
So p is an iterator, *p is an Object pointer, and **p is an Object.
The problem is that this method:
void Engine::killUpdate(std::string command) {
if ((*p)->getIsDead() == true) {
delete *p;
}
}
deallocates the Object pointed to by *p, the pointer in the vector at the position referenced by the p iterator. However the pointer *p itself is still in the vector, now it just points to memory that is no longer allocated. Next time you try to use this pointer, you will cause undefined behavior and very likely crash.
So you need to remove this pointer from your vector once you have deleted the object that it points to. This could be as simple as:
void Engine::killUpdate(std::string command) {
if ((*p)->getIsDead() == true) {
delete *p;
objects.erase(p);
}
}
However, you are calling killUpdate from update in a loop that iterates over the objects vector. If you use the code above, you will have another problem: once you erase p from the objects vector, it is no longer safe to execute p++ in your for-loop statement, because p is no longer a valid iterator.
Fortunately, STL provides a very nice way around this. vector::erase returns the next valid iterator after the one you erased! So you can have the killUpdate method update p instead of your for-loop statement, e.g.
void Engine::update(string command) {
if (getGameOver() == false) {
for (p = objects.begin(); p != objects.end(); /* NOTHING HERE */) {
// ...
killUpdate(command);
}
}
}
void Engine::killUpdate(std::string command) {
if ((*p)->getIsDead() == true) {
delete *p;
p = objects.erase(p);
} else {
p++;
}
}
This is of course assuming that you always call killUpdate in the loop, but I'm sure you can see the way around this if you don't -- just execute p++ at the end of the for-loop body in the case that you haven't called killUpdate.
Also note that this is not particularly efficient, since every time you erase an element of the vector, the elements that follow it have to be shifted back to fill in the empty space. So this will be slow if your objects vector is large. If you used a std::list instead (or if you are already using that), then this is not a problem, but lists have other drawbacks.
A secondary approach is to overwrite each pointer to a deleted object with nullptr and then use std::remove_if to remove them all in one go at the end of the loop. E.g.:
void Engine::update(string command) {
if (getGameOver() == false) {
for (p = objects.begin(); p != objects.end(); p++) {
// ...
killUpdate(command);
}
}
std::erase(std::remove_if(objects.begin(), objects.end(),
[](const Object* o) { return o == nullptr; }),
objects.end());
}
void Engine::killUpdate(std::string command) {
if ((*p)->getIsDead() == true) {
delete *p;
*p = nullptr;
}
}
The assumption this time is that you will never have a nullptr element of objects that you want to keep for some reason.
Since you seem to be a beginner, I should note that this:
std::erase(std::remove_if(objects.begin(), objects.end(),
[](const Object* o) { return o == nullptr; }),
objects.end());
is the erase-remove idiom, which is explained well on Wikipedia. It erases elements from the vector if they return true when a given function object is called on them. In this case, the function object is:
[](const Object* o) { return o == nullptr; }
Which is a lambda expression and is essentially shorthand for an instance of an object with this type:
class IsNull {
public:
bool operator() (const Object* o) const {
return o == nullptr;
}
};
One last caveat to the second approach, I just noticed that you have another loop over objects in scrollUpdate. If you choose the second approach, be sure to update this loop to check for nullptrs in objects and skip them.
Here is an issue (formatted for readability):
void Engine::update(string command)
{
if (getGameOver()==false)
{
for (p=objects.begin();p!=objects.end();p++)
{
spawnUpdate(command); // changes vector
//...
}
}
//...
}
void Engine::spawnUpdate(string command)
{
//...
objects.push_back(new Bullet((*p)->getPosX(),(*p)->getPosY(),(*p)->getState())); // no
//...
}
You have a loop with iterator p that points to elements in the object vector. When you call objects.push_back, the iterator for the vector may become invalidated. Thus that loop iterator p is no longer any good. Incrementing it in the for() will cause undefined behavior.
One way to get around this is to create a temporary vector that holds your updates. Then you add the updates at the end of your processing:
void Engine::update(string command)
{
std::vector<Object*> subVector;
if (getGameOver()==false)
{
for (p=objects.begin();p!=objects.end();p++)
{
spawnUpdate(command, subVector);
//...
}
}
// add elements to the vector
object.insert(object.end(), subVector.begin(), subVector.end());
}
void Engine::spawnUpdate(string command, std::vector<Object*>& subV)
{
if (command.compare("shoot")==0)
{
cout<<"Bang!"<<endl;
if ((*p)->getType() == PLAYER)
subV.push_back(new Bullet((*p)->getPosX(),(*p)->getPosY(),(*p)->getState()));
cout<<"Bullet success "<<endl;
}
}
You could avoid most of these issues by not using raw pointers. Clearly your code uses the semantic that the vector owns the pointers, so you can express this directly:
std::vector< std::unique_ptr<Object> > objects;
Then you may insert into the vector by using objects.emplace_back(arguments,to,Object,constructor); , and when you remove from the vector it will automatically delete the Object.
You still need to watch out for erase invalidating iterators, so keep using the erase-remove idiom as explained by Tyler McHenry. For example:
objects.erase( std::remove_if( begin(objects), end(objects),
[](auto&& o) { return o->getIsDead(); }), end(objects) );
Note - auto&& is permitted here since C++14; in C++11 you'd have to use std::unique_ptr<Object>&. Required includes are <algorithm> and <memory>.
And please stop using global iterators, keep p local to the function and pass any arguments you need to pass.

How to get class objects stored in a list in C++?

I've defined my own class and stored objects of them in a std:list. Now I want to pick up all the elements, but something went wrong - I hope this is not too complicated to read:
std::map < long, FirstClass*> FirstClassMap;
std::map < long, FirstClass* >::iterator it;
it=this->FirstClassMap.begin()
//initialization of FirstClassMap is somewhere else and shouldn't matter.
list<SecondClass*>::iterator ListItem;
list<SecondClass*> depList = it->second->getSecondClassList();
for(ListItem = depList.begin(); ListItem != depList.end(); ++ListItem)
{
/* -- the error is in this Line -- */
FirstClass* theObject = ListItem->getTheListObject();
std::cout << theObject->Name();
}
Then there is the function:
SecondClass::getTheListObject()
{
return this->theObject; //returns a FirstClass object
}
FirstClass::Name()
{
return this->name //returns a string
}
Here I get the Error
Method 'getTheListObject' could not be resolved
and
Error:element request »getTheListObject« in »*
ListItem.std::_List_iterator<_Tp>::operator->()«, whose
pointer type is »SecondClass*« (maybe »->« was meant)
(I'm sorry, that I can't give you the correct error message. I have to translate it from German to English, I don't get these in English)
I don't really see the problem. Has anyone an idea?
Kind Regards
In your code, ListItem isn't an instance of SecondClass*, it's an instance of an iterator of SecondClass*. You have to dereference the iterator to get access to the underlying object. So your for loop should look like:
for(ListItem = depList.begin(); ListItem != depList.end(); ++ListItem)
{
FirstClass* theObject = (*ListItem)->getTheListObject(); //Dereference the iterator,
//then call the method.
std::cout << theObject->Name();
}

Preventing copying of structures - with recursive functions

a very simplistic (and silly) abstraction of what I'm doing is described below:
class A{
private:
template <typename InIt>
A foo(InIt begin, InIt end, A& a) {
// {begin, ind} is a datastructure containing all "terms" to search for.
auto iter(sub.begin());
auto e(sub.end());
// search trough all elements in original structure.
do
if (FUNC) {
if (++begin != end) {
return iter->foo(begin, end, a.append_values(iter));
//append_values appends a copy of the element's values at iter
//does not copy the sub "trees" of the element at "iter"
//it returns a reference to the appended sub "tree"
} else {
return a;
}
}
} while (++iter != e);
return a;
}
};
Sub is a vector containing objects of class "A" - so effectivelly creating a tree-datastructure. FUNC is a function that must be true for the branch to be "added" to the new tree.
What I'm wondering is: how many copys are "created" if, say, the depth (difference between initial begin, end) is "X". - I'm fearing that for each depth a new copy of "a" is created. This is something I wish to prevent. So should I return by reference? - Or by pointer?
UncleBens indeed gave the correct question I needed to find a "solution".
I completely "forgot" you can obviously use arguments-by-reference as output too. I don't have to return anything as I edit the original "a", not a copy.

Strange problem with vectors

I have a really strange problem with stl vectors in which the wrong destructor is called for the right object when I call the erase method if that makes any sense.
My code looks something like this:
for(vector<Category>::iterator iter = this->children.begin(); iter != this->children.end(); iter++)
{
if((*iter).item == item)
{
this->children.erase(iter);
return;
}
-------------------------
}
It's just a simple function that finds the element in the vector which has some item to be searched, and removes said element from the vector. My problem is than when the erase function is called, and thus the object which the iterator is pointing at is being destroyed, the wrong destructor is being called. More specific the destructor of the last element in the vector is being called, and not of the actual object being removed. Thus the memory is being removed from the wrong object, which will still be an element in the vector, and the actual object which is removed from the vector, still has all of it's memory intact.
The costructor of the object looks like this:
Category::Category(const Category &from)
{
this->name = from.name;
for(vector<Category>::const_iterator iter = from.children.begin(); iter != from.children.end(); iter++)
this->children.push_back((*iter));
this->item = new QTreeWidgetItem;
}
And the destructor
Category::~Category()
{
this->children.clear();
if(this->item != NULL)
{
QTreeWidgetItem* parent = this->item->parent();
if(parent != NULL) parent->removeChild(this->item);
delete this->item;
}
}
When you erase your element from the vector, each element after it is copied (using the assignment operator) to the previous spot in the vector. Once this is complete, the last element in the vector is destructed. This could be why you're seeing your last element get destructed. Rule number one when using the STL is to ensure the copy semantics for your object are correct.
You should consider writing an assignment operator:
Category & operator =(const Category & other);
Although this may not be as simple as it sounds, considering objects will be copied and destructed many times in the vector.
You probably should use standard algorithms.
The main issue I see is that your destructor for Category asks its parent vector to remove it. That cannot be right, the destructor happens only when the vector is already removing it.
std::vector uses placement-new so will be calling your destructor directly. I do not know what the effect will be to go back to the vector at this point.
Remove the line if (parent != NULL ) parent->removeChild(this->item) from the destructor. It is not what you want.
This is expected behavior. On my implementation (and I am guessing, on yours) when erasing an element from a vector, elements from n+1 to the end are assigned into it and the very last element is destructed.
Use std::list if you don't want this to happen.
Demo:
#include <iostream>
#include <vector>
struct Category
{
int item;
Category(int n=0) : item(n) {}
~Category() { std::cout << "Category " << item << " destroyed\n"; }
};
int main()
{
std::vector<Category> children(3);
children[0] = Category(0);
children[1] = Category(1);
children[2] = Category(2);
int item = 0;
std::cout << " beginning the loop \n";
for( std::vector<Category>::iterator iter = children.begin();
iter != children.end(); ++iter)
{
if(iter->item == item)
{
children.erase(iter); // prints "Category 2 destroyed"!
break;
}
}
std::cout << " loop done \n";
} // this will print "Category 1 destroyed" and "Category 2 destroyed"
And yes, explicit erase/remove_if is more readable than the loop.