Vectors of Objects and Possible Memory Allocation Error

closed account (DS1Rko23)
I've been working on a large project and have been running into a runtime error. I'm using Codeblocks portable 8.02 on Windows 7 with the GNU GCC compiler. I'm using a vector of objects and have not had a problem using push_back until I started using a vector of strings in the vector of classes, which gives me a runtime error ("[name of application] has stopped working. Windows is checking for a solution to the problem."). I've managed to reproduce the bug with the following lines of code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <vector>
#include <string>

using namespace std;

class C
{
    public:
        vector<string> mystrings;
};

int main()
{
    vector<C> Objects;
    Objects.push_back(C());
    Objects[0].mystrings.push_back("Hello");
    Objects[1].mystrings.push_back("World"); //take this line of code out and   it works fine
    Objects.push_back(C()); //here's where it breaks
    return 0;
}


I believe that the problem occurs when mystrings allocates more memory while the Objects vector does not, but have no idea how to fix it. Ideally, the solution wouldn't include pointers as I'm not very experienced with them yet - but if it does, then I guess I'll have to learn a bit more ;).

Also: I tested this with arrays replacing the vectors, and the same problem occurred. If possible, an explanation of why the solution works would be great; thanks in advance!
Maybe you need to make a new constructor that can handle the idea of having a pre-initialized variable passed in to it.

EDIT: If you're using more than one vector, and more than one function, to handle your class, you *need* pointers.
Last edited on
Actually, it occurs to me that there is no Objects[1] until after the second Objects.push_back(); How does this work:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <vector>
#include <string>

using namespace std;

class C
{
	public:
		vector<string> mystrings;
};

int main()
{
	vector<C*> Objects;
	vector<C*>::iterator it;
	C *temp = new C;
	string tmpStr;
	Objects.push_back(temp);
	(*Objects)->mystrings.push_back("Hello");
	(*Objects)->mystrings.push_back("World");
	Objects.push_back(temp);
	return 0;
}


EDIT: Added (*) to pointer pointer Objects
Last edited on
closed account (DS1Rko23)
The compiler issues an error:
error: no match for 'operator*' in '*Objects'.

If I try switching that to a reference (replacing (*Objects) with (&Objects)), I am warned that there is no member of vector<C*> named mystrings...Thanks for the quick reply, by the way.
1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
	vector<C*> Objects;
	vector<C*>::iterator it;
	C *temp = new C;
	string tmpStr;
	Objects.push_back(temp);
	it = Objects.begin();
	(*it)->mystrings.push_back("Hello");
	(*it)->mystrings.push_back("World");
	Objects.push_back(temp);
	return 0;
}


Try this.
Additionally, here's an example that I think you'll be able to get something out of:
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
character * newCharacter();

class characterSet {
	vector<int> x;
	list<character*> characters;
	list<character*>::iterator it;
	character *temp;
	string name;
	int selection, dice, tempInt;
	ofstream mySaveFile;
	ifstream myOpenFile;
public:
	void showMenu();
};

void characterSet::showMenu(){
	cout << "***************************" << endl;
	cout << "*  Make a selection:      *" << endl;
	cout << "*    1) New Character     *" << endl;
	cout << "*    2) Delete Character  *" << endl;
	cout << "*    3) Save Characters   *" << endl;
	cout << "*    4) Open Characters   *" << endl;
	cout << "*    5) Print Characters  *" << endl;
	cout << "*    6) Roll Dice         *" << endl;
	cout << "*    0) Exit              *" << endl;
	cout << "***************************" << endl;
	cout << "Menu$ ";
	cin >> selection;
	switch (selection){
		case 1:
			temp = newCharacter();
			characters.push_back(temp);
			it = characters.begin();
			while(it != characters.end()){
				(*it)->printStats();
				++it;
			}
			break;
		case 2:
			cout << "Enter the character name to delete." << endl;
			cout << "Delete$ ";
			cin >> name;
			it = characters.begin();
			while(it != characters.end()){
				if((*it)->charName == name){
					delete *it;
					it = characters.erase(it);
				}
				else{++it;}
			}
			break;
		case 3:
			mySaveFile.open("save.txt");
			it = characters.begin();
			while(it != characters.end()){
				mySaveFile << " " << (*it)->charName << " " << (*it)->ringVoid << " " << (*it)->statStam << " " << (*it)->statWill << " " << (*it)->statRef << " ";
				mySaveFile << (*it)->statInt << " " << (*it)->statStr << " " << (*it)->statPercp << " " << (*it)->statAgil << " " << (*it)->statAware;
				++it;
			}
			mySaveFile.close();
			break;
		case 4:
			myOpenFile.open("save.txt");
			it = characters.begin();
			while(!myOpenFile.eof()){
				myOpenFile >> name;
				for(int i = 0; i < 9; i++){
					myOpenFile >> tempInt;
					x.push_back(tempInt);
				}
				temp = new character(name, x);
				characters.push_front(temp);
				x.clear();
			}
			myOpenFile.close();
			break;
		case 5:
			cout << "Enter the character to print." << endl;
			cout << "Print$ ";
			cin >> name;
			it = characters.begin();
			while(it != characters.end()){
				if((*it)->charName == name){
					(*it)->printStats();
					++it;
				}
				else{++it;}
			}
			break;
		case 6:
			cout << "Enter the character to roll for." << endl;
			cout << "Roll$ ";
			cin >> name;
			it = characters.begin();
			while(it != characters.end()){
				if((*it)->charName == name){
					dice = diceRoller((*it)->statStam, (*it)->statWill);
					cout << "Rolled a " << dice << endl;
					++it;
				}
				else{++it;}
			}
			break;
		case 0:
			exit(0);
			break;
		default:
			cout << "Invalid choice" << endl;
			break;
	}
	showMenu();
}

//This public function gets variables for the character name and stats from the user, creates a pointer to a new character, and passes the new character pointer back to the menu function.
character * newCharacter(){
	vector<int> stats;
	int temp;
	string name, statNames[9] = {"Void Ring", "Stamina", "Will", "Reflex", "Intelligence", "Strength", "Perception", "Agility", "Awareness"};
	cout << "Character Name:" << endl << "New$ ";
	cin >> name;
	for(int i = 0; i < 9; i++){
		cout << "Enter the character's " << statNames[i] << "." << endl << "New$ ";
		cin >> temp;
		stats.push_back(temp);
	}
	character *newChar = new character(name, stats);
	return newChar;
}

You'll notice in this snippet that I created a pointer function. You can do this, and in fact have to, in order to create a pointer inside of the function and then return the pointer instead of the whole class, which can be unwieldy.
Last edited on
closed account (DS1Rko23)
That works. Is there a more efficient way to change the iterator to higher values than just using Objects.begin() followed by it++? It's doable, and I could easily make a function to access a certain point, but why reinvent the wheel (unless it's to make it better ;))?

Thanks, by the way!

EDIT: thanks for the great example. I will definitely be able to learn from it! I've been practically avoiding pointers, mainly because I haven't understood them, but I think I'm starting to figure out a LITTLE bit about them.
Last edited on
That's the best way to iterate that I know of, but if you know specifically where in your vector something is stored, you can just jump right to it. The point of the iterator is that it's independent of any values contained in the list, vector or deque, but it still can point to objects inside that list, so you can move it around freely. With a vector, everything is sequential in memory, which can cause problems with reallocation, but in lists, you don't have that problem, and iterators become even more powerful, because even without the list being stored next to each other in memory, your iterator still knows the memory address of the next item in the list. (It doesn't know the value, just the address, which is why it's a double pointer, not a single.)
closed account (DS1Rko23)
Alright. Making my own function to handle it shouldn't be to challenging. I'll also try a list out sometime soon. I won't try it today, though, because I just recently tried out multimaps, maps, and sets for the first time (they're in the program I was having a problem with). They look pretty useful, and I just checked the documentation on them. I'm heading out for now, but thanks again for the help! I've been teaching myself as I go, creating programs as I need them, and it's really nice to know that when I'm really struggling I can find help.
Just as an aside, trailken, if you don't understand pointers, you should probably go back and look in to them very, very thoroughly, because once you start with classes, you're never going to be able to avoid pointers, past the simple life of programs with classes that don't interact.
Topic archived. No new replies allowed.