Hi, I'm a beginner to C++ and am having some trouble with my list. I first define a struct named "bullet' like so:

struct bullet {
	bool alive;

	bullet()
		alive = true;
};

Then, I create a list of objects of type "bullet": list<bullet> bullet_list; In my program, I frequently add new bullets to the list and delete them. At first, I was using a vector, but then I read that using a list was better for my uses because of how often I create/delete bullets from various positions in the list (I actually did this so frequently that I would get buffer overrun errors, which is why I'm now trying lists).

Anyways, when I was using a vector, I could use the following code to check if the bullet was still "alive":

for (int i=0; i < bullet_list.size(); i++) {
	bool isalive = bullet_list[i].alive;
	// do stuff

But now that I am using a list, I cannot. I get the following error: Error 1 error C2676: binary '[' : 'std::list<_Ty>' does not define this operator or a conversion to a type acceptable to the predefined operator What do I have to change in order to make this work?

Thanks in advance.

Recommended Answers

All 12 Replies

Try

for (list<bullet>::iterator i = bullet_list.begin(); i != bullet_list.end(); ++i) {
	bool isalive = i->alive;
	// do stuff

Edit: Lists dont got the [] operator because it would be very slow, so you have to work with iterators.

Wow, when I use that code you gave me, I get a whopping 104 errors! New record, baby. Well I guess I should post my real code, since I do quite a bit while iterating.
Code:

struct bullet {
	float x, y, z;
	float dx, dy, dz;
	int id;
	float traveledX, traveledY, traveledZ;
	bool alive;

	bullet(int bulletID) {
		id = bulletID;
		traveledX = 0.0;
		traveledY = 0.0;
		traveledZ = 0.0;
		alive = true;
	}

	void create() {
		// game code to create object
	}

	bool move() {
		// code
		return alive;
	}


	bool checkCollision(float oldX, float oldY, float oldZ) {
		// game code to check collision
		return collides;
	}
};

list<bullet> bullet_list;
list<bullet>::iterator iter;



bool alive = false;
for (iter = 0; iter < bullet_list.end; ++iter) {
	bool isalive = iter->alive;
	if (isalive == true) {
		alive = iter->move(); // move is a function inside the struct "bullet"
	} 
	if (alive == false) {
		int bulletID = iter->id;
		bullet_list.erase(bullet_list.begin()+iter);
		dbDeleteObject(bulletID); // deletes object from game
	}
}

As for the errors....I'll just put in a few. It looks like some of the errors are duplicates:

Error 1 error C2679: binary '=' : no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion)

Error 2 error C2784: 'bool std::operator <(const std::list<_Ty,_Ax> &,const std::list<_Ty,_Ax> &)' : could not deduce template argument for 'const std::list<_Ty,_Ax> &' from 'std::list<_Ty>::_Iterator<_Secure_validation>'

Error 8 error C2784: 'bool std::operator <(const std::vector<_Ty,_Alloc> &,const std::vector<_Ty,_Alloc> &)' : could not deduce template argument for 'const std::vector<_Ty,_Alloc> &' from 'std::list<_Ty>::_Iterator<_Secure_validation>'

Error 14 error C2784: 'bool std::operator <(const std::stack<_Ty,_Container> &,const std::stack<_Ty,_Container> &)' : could not deduce template argument for 'const std::stack<_Ty,_Container> &' from 'std::list<_Ty>::_Iterator<_Secure_validation>'

Error 20 error C2784: 'bool std::operator <(const std::deque<_Ty,_Alloc> &,const std::deque<_Ty,_Alloc> &)' : could not deduce template argument for 'const std::deque<_Ty,_Alloc> &' from 'std::list<_Ty>::_Iterator<_Secure_validation>'

EDIT: The code that causes errors is all lines 38+.

If you would like to see the rest, let me know, but I hope this will suffice.

How can I fix these?

Thanks again.

Wow, when I use that code you gave me, I get a whopping 104 errors! New record, baby. Well I guess I should post my real code, since I do quite a bit while iterating.

As for the errors....I'll just put in a few. It looks like some of the errors are duplicates:

EDIT: The code that causes errors is all lines 38+.

If you would like to see the rest, let me know, but I hope this will suffice.

How can I fix these?

Thanks again.

std::list<bullet> bullet_list;
	std::list<bullet>::iterator iter;



	bool alive = false;
	for (iter = bullet_list.begin(); iter != bullet_list.end(); ++iter) {
		bool isalive = iter->alive;
		if (isalive == true) {
			alive = iter->move(); // move is a function inside the struct "bullet"
		} 
		if (alive == false) {
			int bulletID = iter->id;
			bullet_list.erase(iter);
			dbDeleteObject(bulletID); // deletes object from game
		}
	}

Changes to lines 7 & 14.

With bullet_list.erase(bullet_list.begin()+iter); is fixed when just making it iter, since by the looks of it you were attempting to delete the element where the iterator is currently placed. Anyway depends on rest of your code but with commenting out 1 or 2 lines which weren't defined with the rest of the code available, I got that to compile without error once the changes were made, of course don't know if it works as you'd expect, since being 3AM my brain is a little fried now too! :)

Well, good news and bad news! As for the good news, the code that you provided gets rid of compiler errors! However, for the bad news, I'm still getting a bad error in-game.

Since the error is related to this code, I'll just keep it going in this thread. So, let me give you some background information about my game. It is a FPS-type game, so in the simplest manner, you have a gun and you shoot at enemies by clicking the mouse. During the game loop, I run the above function to check whether or not each bullet is still in play. If they are, each bullet is moved forward by a certain velocity; if not, they are removed from the game.

My problem, as Visual C++ 2008 puts it, is this:

Unhandled exception at 0x0012276a in (Game Name).exe: 0xC0000005: Access violation writing location 0x63207465.

I posted about this on Dark GDK's (game library I use) forum, and they said it was unrelated to the library and that it was just a C++ error. So, that brings me here! Why am I getting the error? I'm almost positive it has to do with the manipulation of my bullet_list, as if I don't remove anything from the list, I don't get the error. I think that sometimes when I shoot new bullets, the program is not quite done deleting the old bullets from the list, so it ends up writing over the old list, causing it to write over itself in memory. Is this correct?

If it helps, when I receive the error, Visual C++ brings up line 800 of the "list" library: _Nextnode(_Prevnode(_Pnode)) = _Nextnode(_Pnode); Does anybody know how I can fix this error?

Thanks again.

Wow, when I use that code you gave me, I get a whopping 104 errors! New record, baby. Well I guess I should post my real code, since I do quite a bit while iterating.

I apologize, i forgot to mention a few things.

#include <list> // new
#include <iterator> // new
using namespace std; // new
for (list<bullet>::iterator i = bullet_list.begin(); i != bullet_list.end(); ++i) {
	bool isalive = i->alive;
	// do stuff

This code doesn't work:

std::list<bullet> bullet_list;
std::list<bullet>::iterator iter;

bool alive = false;
for (iter = bullet_list.begin(); iter != bullet_list.end(); ++iter) {
	bool isalive = iter->alive;
	if (isalive == true) {
		alive = iter->move(); // move is a function inside the struct "bullet"
	} 
	if (alive == false) {
		int bulletID = iter->id;
		bullet_list.erase(iter);
		dbDeleteObject(bulletID); // deletes object from game
	}
}

The problem is in line 12. Executing bullet_list.erase(iter); causes the element to which iter refers to be deleted from the list. Doing sinvalidates iter. On the next trip through the while loop, iter is invalid, so ++iter has undefined effect.

One way to deal with this problem is to increment iter only when it is known to be valid. The following rewrite is slightly sneaky, but I think it will work:

std::list<bullet> bullet_list;
std::list<bullet>::iterator iter;

bool alive = false;
for (iter = bullet_list.begin(); iter != bullet_list.end(); ) {  // No increment!
	bool isalive = iter->alive;
	if (isalive == true) {
		alive = iter->move(); // move is a function inside the struct "bullet"
	}

	// The following if statement increments iter one way or another,
	// regardless of the value of alive
	if (alive)
		++iter;
	else {
		int bulletID = iter->id;
		bullet_list.erase(iter++);
		dbDeleteObject(bulletID); // deletes object from game
	}
}

The point is that bullet_list.erase(iter++); copies iter , increments it (which causes it to refer to a value that will survive the call to erase , and then erases the element to which iter formerly referred. This erasure is perfectly safe, and ensures that the value of iter is appropriate for the next time through the loop.

commented: I don't like giving broken code but it sometimes happens, thanks for correcting it. +2

EDIT: Perfect! It works! Thank you so much! So I can hopefully avoid this in the future, could you explain to me what the difference between "++iter" and "iter++" is? They seem to be performing different functions and I would love to know how you came up with this brilliant piece of code. I can see how you are incrementing iter when the bullet is alive, but why do you pass iter++ to bullet_list.erase ? Why doesn't it erase the next bullet in the list instead of the current one?

Thanks everybody for all your help.

This code doesn't work:

std::list<bullet> bullet_list;
std::list<bullet>::iterator iter;

bool alive = false;
for (iter = bullet_list.begin(); iter != bullet_list.end(); ++iter) {
	bool isalive = iter->alive;
	if (isalive == true) {
		alive = iter->move(); // move is a function inside the struct "bullet"
	} 
	if (alive == false) {
		int bulletID = iter->id;
		bullet_list.erase(iter);
		dbDeleteObject(bulletID); // deletes object from game
	}
}

The problem is in line 12. Executing bullet_list.erase(iter); causes the element to which iter refers to be deleted from the list. Doing sinvalidates iter. On the next trip through the while loop, iter is invalid, so ++iter has undefined effect.

One way to deal with this problem is to increment iter only when it is known to be valid. The following rewrite is slightly sneaky, but I think it will work:

std::list<bullet> bullet_list;
std::list<bullet>::iterator iter;

bool alive = false;
for (iter = bullet_list.begin(); iter != bullet_list.end(); ) {  // No increment!
	bool isalive = iter->alive;
	if (isalive == true) {
		alive = iter->move(); // move is a function inside the struct "bullet"
	}

	// The following if statement increments iter one way or another,
	// regardless of the value of alive
	if (alive)
		++iter;
	else {
		int bulletID = iter->id;
		bullet_list.erase(iter++);
		dbDeleteObject(bulletID); // deletes object from game
	}
}

The point is that bullet_list.erase(iter++); copies iter , increments it (which causes it to refer to a value that will survive the call to erase , and then erases the element to which iter formerly referred. This erasure is perfectly safe, and ensures that the value of iter is appropriate for the next time through the loop.

Oops, my bad... I had a feeling something were slightly up but being so tired it didn't twig. Thanks for the correction.

EDIT: Perfect! It works! Thank you so much! So I can hopefully avoid this in the future, could you explain to me what the difference between "++iter" and "iter++" is? They seem to be performing different functions and I would love to know how you came up with this brilliant piece of code. I can see how you are incrementing iter when the bullet is alive, but why do you pass iter++ to bullet_list.erase ? Why doesn't it erase the next bullet in the list instead of the current one?

Thanks everybody for all your help.

++iter & iter++ refer to both pre-increment & post-increment, pre-increment increases the value before the expression is evaluated, post-increment as you guessed increases the value after the expression but he does say why it doesn't erase the next bullet in the list, it copies iter, increments it then erases the element it formerly referred too.

Here is what people usually do when creating a bullet class. Because bullets get
created and destroyed so fast, and because there are so many of them or can be. You
are better of using some raw arrays instead. Put a maximum cap on the number of bullets created. For example you can do something like this :

struct Bullet{
  vector3f startPosition;
  vector3f velocity;
};

template<int SIZE>
class BulletArray {
 private:
  boost::array<Bullet,SIZE> bulletList;
  int currentSize;
 public:
 BulletArray(): currentSize(){}
 bool addBullet(const Bullet& b){ 
    if(isBulletFull()) return false;
    bulletList[currentSize++] = b;
    return true;
 }
 //...more methods
};

How did I come up with it?

If you execute bullet_list.erase(iter) , that invalidates iter . So before executing bullet_list.erase(iter) , it is necessary to compute the new value to be placed into iter , because there will be no opportunity to do so later.

Here's the straightforward way to do it:

std::list<bullet>::iterator temp = iter;
++iter;
bullet_list.erase(temp);

This part of the solution is pretty simple. I guess it's a creative step to realize that

bullet_list.erase(temp++);

does exactly the same thing, and it's hard to explain why I happened to think of it.

It helps to have been using C++ for 25 years.

Thank you everybody for all your help. All of your explanations really helped me; I understand it pretty well. And thanks for the suggestion firstPerson, I might use that in the future, but currently that is above my level and I don't like to use others' code especially when I have no idea how it works.

Thanks again everybody.

Problem solved.

#include<stdafx.h>
#include<stdio.h>
#include<stdlib.h>
#include<iostream>

struct node
{
    //char _char;
    int number;
    struct node *next;
};
void insertion(struct node *list,int num);
int search(struct node *list,int num);
void display(struct node *list);
void delete_node(struct node *list,int num);

int main()
{
int num=0;
int input=1;
int retval=0;
/********************************************/

struct node *list = NULL;
//list=(struct node*)malloc(sizeof(struct node));        ///  remove the first node    else do it with class
//list->number=0;
//list->next=NULL;
/***************************************************/

while(input!=0)
{

    printf("\n\n------ MENU SELECTION------\n");
    printf("\t00) QUIT\n");
    printf("\t01) INSERTION\n");
    printf("\t02  SEARCH\n");
    printf("\t03  DISPLAY\n");
    printf("\t04  DELETION \n");
      scanf("%d",&input);
    switch(input)
    {
    case 0:

    default:
        printf("good bye\t");
        input=0;
        break;
    case 1:

            printf("\nYour choise 'INSERTION'\n");
            printf("enter value you want to insert ::  \t");
            scanf("%d",&num);
            insertion(list,num);  
            printf("\t\t  The value inserted is %d",num);
            break;

    case 2:

        printf("your choise :: 'SEARCH'\n");
        printf("Please enter the number you want to search  ::   ");
            scanf("%d",&num);
            if ((retval=search(list,num))==-1)              //function call
                printf("\n\tRESULT  ::Value '%d' not found",num);
            else
                printf("The value '%d' is found and its location is %d\t",num,retval);

            break;  

    case 3:

        printf("your choise : DISPLAY\n");
        printf("List is ::\t");
            display(list);
            break;

    case 4:

         printf("\tYour choise is 'DELETION'\n");
         printf("Enter the number you want to delete  ::   ");
         scanf("%d",&num);
         delete_node(list,num);

        break;

    }//end switch
}//end while

free(list);
return(0);
}

void display(struct node *list)
{
    while(list->next!= NULL)
    {
        printf("\t%d\t",list->next->number);
        list=list->next;
    }
    if (list->number==0)
        printf("NO DATA (LIST IS EMPTY)");

}
void insertion(struct node *list,int num) 
{
    /**************************************/
    if (*list == NULL)
    {
    list=(struct node*)malloc(sizeof(struct node));
    list->number=num;
    list->next= NULL;
    return;
    }
/**************************************************/

    while(list->next!= NULL)
    list=list->next;

        list->next=(struct node*)malloc(sizeof(struct node));
        list->next->number=num;
        list->next->next= NULL;


}

void delete_node(struct node *list,int num)
{
    int retval=0;

    if ((retval=search(list,num))==-1)            
 printf("\n\tSORRY No such node found");

    else
    {   
    struct node *temp;
  temp=(struct node*)malloc(sizeof (struct node));

  while(list->next->number!=num)
 list=list->next;

  temp=list->next->next;
  free(list->next);
  list->next=temp;
  printf("\tDeleted number is %d",num);
  //printf("  and updated list shown below:: \n");
  //display(list);
    }
 }

int search(struct node *list,int num)
{
    int retval= -1;
    int i=1;
    while(list ->next!= NULL )
    {
        if (list->next->number==num)
            return i;
        else 
    i++;
    list = list->next;
    }
    return retval;
}



///////plz remove error  but dont create a extra node
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.