Iterator

closed account (10oTURfi)
How do I make iterator point to random object in a standard list?
Last edited on
A std::list does not provide a random access iterator as std::vector. With a vector, you can reference a particular item by its sequential position.

Is that what you're looking for, or am I misinterpreting your question?
Using std::advance:
1
2
3
list<foo> myList;
list<foo>::iterator it=myList.begin();
advance(it,rand()%myList.size()); //requires the list to be not empty 
closed account (10oTURfi)
@Athar I'll test it out. Looks like thats it.

edit: btw, thanks!
Last edited on
Note however that such accesses are expensive in a std::list (running in linear time).
Perhaps a vector really is the better choice in this case.
closed account (10oTURfi)
Hmm in that case i replaced the list with vector, but I get a runtime error:
Vector iterator not dereferancable
whatever the hell that means

Also error doesnt pop up every time program is ran, only randomly.
here is the main.cpp :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
	vector<bunny> bunny_list;
	vector<bunny>::iterator iter;

	//Begin with 5 bunnies
	for(int i=0; i<5; i++)
		bunny_list.push_back(bunny());

	//Aging
	for(iter=bunny_list.begin(); iter!=bunny_list.end(); iter++){
		iter->aging();

		//Dying
		if((iter->getVamp()) && (iter->getAge()==50))
			bunny_list.erase(iter);
		else if(!(iter->getVamp()) && iter->getAge()==10)
			bunny_list.erase(iter);
	}

	//Breeding
	for(iter=bunny_list.begin(); iter!=bunny_list.end(); iter++){
		if(iter->getSex() == 'M')
			BreedingMale = true;
		else if(iter->getSex() == 'F')
		{
			BreedingFemale = true;
			num_BreedingFemale++;
		}
	}
	//New bunnies born!
	if(BreedingMale && BreedingFemale)
		for(int i=0; i<num_BreedingFemale; i++)
			bunny_list.push_back(bunny());

	//Turning other bunnies to vamps
	for(iter=bunny_list.begin(); iter!=bunny_list.end(); iter++){
		if(iter->getVamp())
			num_vamps++;
	}
	for(int i=0; i!=num_vamps; i++){
		advance(iter,rand()%bunny_list.size());
		while(true)
			if(!(iter->getVamp())){
				iter->setVamp();
				break;
			}
			else
				advance(iter,rand()%bunny_list.size());
	}

	//Food Shortage
	if(bunny_list.size()>100)
		for(int i=0; i!=50; i++){
			advance(iter,rand()%bunny_list.size());
			bunny_list.erase(iter);
		}
Well, first, before you call advance, you have to make sure iter points to the first element.
Second, when you call erase on an iterator, you invalidate it, so you can't increment it anymore.
However, erase returns the next valid iterator, so you can do this:

1
2
3
4
5
6
7
8
9
10
11
for(iter=bunny_list.begin(); iter!=bunny_list.end();)
{
  iter->aging();

  //Dying
  if ((iter->getVamp() && iter->getAge()==50) ||
      !(iter->getVamp() && iter->getAge()==10))
        iter=bunny_list.erase(iter);
  else ++iter;

}


Edit: if you're using C++11, it's better to use std::remove_if and a lambda function.
The above method runs in quadratic time, while remove_if runs in linear time.
http://www.cplusplus.com/reference/algorithm/remove_if/
Last edited on
closed account (10oTURfi)
Oh one more thing:
How can I use file output/input inside constructor/destructor of a class? (inheritance? lol)
Last edited on
Not sure what you mean.
You do it like you would do it anywhere else... but that seems obvious and certainly doesn't involve inheritance, so you might want to elaborate.
Just a small comment on the use of vector. A vector provides random access, which is what you probably want. The catch is that vectors can have expensive insertion/deletion because they are stored contiguously. A deque may be a better choice, IF there will be a lot of insertion/deletion.
closed account (10oTURfi)
Ah nvm about files, I did open file in some other function, and probably thats why I had some weird error messages...
Last edited on
closed account (10oTURfi)
EDIT: Removed long source.
Last edited on
I agree with moorecm -- that you should use a deque, rather than a list. Then you can ditch the advance.

You aging loop doesn't look quite right. You need

iter = bunny_list.erase(iter);

rather than just

bunny_list.erase(iter);

( Note that you don't need a lambda function to use std::remove_if: you can use a function or (preferably) a functor instead. So you don't have to wait for C++0x (or use Boost) )

I would prob. use a global ofstream in this case. A global logger is one of the few exceptions I make to the "no globals" edict. (I am assuming that the lifetime of all your bunny objects is limited to main)

But what to you mean by "not working properly"?

Andy

P.S. If you do go with the remove_if solution, you have to remember to use the "erase remove idiom" (http://en.wikipedia.org/wiki/Erase-remove_idiom)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    class TimeToDie
    : public unary_function<bunny&, bool> // from <functional>
    {
    public:
        // bunny ref is not const as it has to age
        bool operator()(bunny& b) const
        {
            b.aging();

            return (    ( b.getVamp() && (b.getAge()==50))
                     || (!b.getVamp() && (b.getAge()==10)) );
        }
    };

    // remove_if is from <algorithm>
    bunny_list.erase(remove_if(bunny_list.begin(), bunny_list.end(), TimeToDie()), bunny_list.end());

Last edited on
closed account (10oTURfi)
EDIT: Nvm figured it out as well
Last edited on
Add more logging!!!
closed account (10oTURfi)
Add more logging!!!


What? :O
You said you didn't know where the error is/was. More logging would have prob. helped you locate the prob.

Btw - you shouldn't delete content from the thread, as it makes the replies meaningless. So someone reading the thread in the future won't find it much use.

Andy

closed account (10oTURfi)
You said you didn't know where the error is/was. More logging would have prob. helped you locate the prob.

Btw - you shouldn't delete content from the thread, as it makes the replies meaningless. So someone reading the thread in the future won't find it much use.

Andy


Thanks for the advice. I usedcoutto get whats happening and it seem to help alot!
closed account (10oTURfi)
One more tiny problem: One bunny infects everyone in single turn. No damn idea how that happened:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*Why the hell did i use the BOOLEAN variable? fix that
One bunny infects them all
Add the board
Remove the cout, found the problem
*/
#include "header.h"

int main(){
	//Init
	int turn = 0;
	bool BreedingMale;
	bool BreedingFemale;
	bool BOOLEAN;
	int num_BreedingFemale;
	int num_vamps;
	int num_bunnies;
	srand(time(NULL));
	vector<bunny> bunny_list;
	vector<bunny>::iterator iter;
	ofstream File("Bunny File Output.txt");
	File << "Turn " << turn << endl;

	//Begin with 5 bunnies
	for(int i=0; i<5; i++){
		bunny_list.push_back(bunny());
		iter = --bunny_list.end();
		if(iter->getVamp())
			File << "Radioactive Mutant Vampire Bunny " << iter->getName() << " is born!" << endl;
		else if(!(iter->getVamp()))
			File << "Bunny " << iter->getName() << " is born!" << endl;
	}

	while(!bunny_list.empty()){
		//Reset
		cout << "Reseting" << endl;
		iter = bunny_list.begin();
		BreedingMale = false;
		BreedingFemale = false;
		num_BreedingFemale = 0;
		num_vamps = 0;
		num_bunnies = 0;
		turn++;

		File << "Turn " << turn << endl;
		cout << "Turn " << turn << endl;

		//Aging
		cout << "Aging and Dying" << endl;
		for(iter=bunny_list.begin(); iter!=bunny_list.end();){
			iter->aging();

			//Dying
			BOOLEAN = iter->getVamp();
			if(!(BOOLEAN) && (iter->getAge()==10)){
				File << "Bunny " << iter->getName() << " has died!" << endl;
				iter = bunny_list.erase(iter);
			}
			else if(BOOLEAN && iter->getAge()==50){
				File << "Radioactive Mutant Vampire Bunny " << iter->getName() << " has died!" << endl;
				iter = bunny_list.erase(iter);
			}
			else ++iter;
		}

		//Breeding
		cout << "Breeding" << endl;
		for(iter=bunny_list.begin(); iter!=bunny_list.end();){
			if(iter->getSex() == 'M')
				BreedingMale = true;
			else if(iter->getSex() == 'F')
			{
				BreedingFemale = true;
				num_BreedingFemale++;
			}
			++iter;
		}
		//New bunnies born!
		cout << "New bunnies born!" << endl;
		if(BreedingMale && BreedingFemale)
			for(int i=0; i<num_BreedingFemale; i++){
				bunny_list.push_back(bunny());
				iter = --bunny_list.end();
				if(iter->getVamp() == 1)
					File << "Radioactive Mutant Vampire Bunny " << iter->getName() << " was born!" << endl;
				else if(iter->getVamp() != 1)
					File << "Bunny " << iter->getName() << " was born!" << endl;
			}
	
		//Turning other bunnies to vamps
		cout << "Getting num of vamps" << endl;
		for(iter=bunny_list.begin(); iter!=bunny_list.end();){
			if(iter->getVamp())
				num_vamps++;
			++iter;
		}
		cout << "Getting num of all bunnies" << endl;
		for(iter=bunny_list.begin(); iter!=bunny_list.end();){
			num_bunnies++;
			++iter;
		}
		cout << "There are " << num_bunnies << " bunnies overall" << endl;
		cout << "There are " << num_vamps << " vampires." << endl;
		cout << "Turning bunnies to vamps" << endl;
		if(num_vamps > 0){
			for(int a=0; a<num_vamps; a++){
				while(true){
					iter = bunny_list.begin();
					advance(iter,rand()%bunny_list.size());
					if(!(iter->getVamp())){
						iter->setVamp();
						num_vamps++;
						File << "Bunny " << iter->getName() << " was infected!" << endl;
						break;
					}
					else if(num_bunnies == num_vamps)
						break;
				}
			}
		}

		cout << "Bunnies successfuly turned to vamps" << endl;
		//Food Shortage
		if(bunny_list.size()>100){
			cout << "Food Shortage" << endl;
			File << "Food Shortage!!" << endl;
			for(int i=0; i!=50; i++){
				iter = bunny_list.begin();
				advance(iter,rand()%bunny_list.size());
				if(iter->getVamp())
					File << "Radioactive Mutant Vampire Bunny " << iter->getName() << " has died!" << endl;
				else File << "Bunny " << iter->getName() << " has died!" << endl;
				iter = bunny_list.erase(iter);
			}
		}

		//Print all bunnies!
		cout << "Printing all bunnies..." << endl;
		File << endl;
		for(iter = bunny_list.begin(); iter != bunny_list.end(); iter++)
			File << "Age: " << iter->getAge() << "\t Sex: " << iter->getSex() << "\t Color: " << iter->getColor() << "\t Name: " << iter->getName() << endl;
		File << endl;

		cout << endl;
	}

	File.close();

	return 0;
}
Last edited on
Topic archived. No new replies allowed.