Creating a List of Objects

Hello :D

When creating a list of objects, how do you create new objects inside the list? Here is an example of what I am talking about:

1
2
3
4
5
6
7
#include <list>

class CBlah {
//...
}

std::list<CBlah> lBlah;


Now, I have tried the following and neither have worked

1
2
3
4
5
6
7
8
9
// First, I tried this
lBlah.push_front(CBlah);

// Then, I tried this
lBlah.push_front(CBlah blahObject1);

// Next, I tried this
CBlah blahObject1;
lBlah.push_front(blahObject1);


All of these give me errors. So now I'm wondering how exact lists function when they are based on a custom class. Can anybody shed some light on this for me?

Also, I would like to know how I would go about creating a bunch of objects inside this list without knowing how many I may need to create. In other words, I am creating a list of objects where there may end up being anywhere from 10 to 100 objects in the list.

Thanks ahead of time!
Lines 8/9 should be correct if you've defined a default constructor for your class. Line 2 could be lBlah.push_front(CBlah()); // call constructor as parameter . What are the errors you are getting?
Here is a list of the errors I am getting:

1>libcpmtd.lib(xdebug.obj) : warning LNK4098: defaultlib 'libcmt.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
1>libcpmtd.lib(stdthrow.obj) : error LNK2019: unresolved external symbol __CrtDbgReportW referenced in function "void __cdecl std::_Debug_message(wchar_t const *,wchar_t const *,unsigned int)" (?_Debug_message@std@@YAXPB_W0I@Z)
1>libcpmtd.lib(xdebug.obj) : error LNK2019: unresolved external symbol __malloc_dbg referenced in function "void * __cdecl operator new(unsigned int,struct std::_DebugHeapTag_t const &,char *,int)" (??2@YAPAXIABU_DebugHeapTag_t@std@@PADH@Z)
1>libcpmtd.lib(xdebug.obj) : error LNK2019: unresolved external symbol __free_dbg referenced in function "void __cdecl operator delete(void *,struct std::_DebugHeapTag_t const &,char *,int)" (??3@YAXPAXABU_DebugHeapTag_t@std@@PADH@Z)
fatal error LNK1120: 3 unresolved externals

Here is what my code actually looks like (cut out what wasn't needed):
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
// Header file
#include <list>
#include "time.h"
#include "Laser.h"

class CWorld {
public:
	CWorld();
	~CWorld();
	void worldUpdate();

private:
	std::list<CLaser> lLaser;
        clock_t laserTimer1;
};

// Cpp file
#include "World.h"
#include <list>
#include "time.h"
#include "Laser.h"

using namespace std;

CWorld::CWorld() {
}

CWorld::~CWorld() {
}

void CWorld::worldUpdate() {

	//----------------- Laser creation and handling -----------------
	if (laserTimer1 <= clock()) {
		lLaser.push_front(CLaser());
	}
}

// this is what my laser class looks like
class CLaser {
public:
	CLaser();
	CLaser(float,float,float);
	~CLaser();
	void updateLaser();
private:
	float lasX, lasY, xVelocity;
};


I am essentially creating a list that will handle the lasers in the game I am creating. However, I am getting these errors when I try using the list.
Your errors look like a problem with linking in a library. There is nothing wrong with your list. What compiler are you using and what libraries are you trying to link to?
I am using Visual C++ 2008 Express Edition. I have noticed that whenever I remove the line lLaser.push_front(CLaser()); then it removes all my errors. The only libraries I am using are the time.h and <list> libraries as shown with the exception of my own header files. Although I am using the DarkGDK to create this game with but I don't think that could have any relation to this. http://www.thegamecreators.com/?m=view_product&id=2128
Move or declare the CLaser class above the CWorld::worldUpdate() function.
Well, my code doesn't actually look like that. In reality, all of my classes are created in their own header files along with their functions in their own cpp file. The only reason it is shown below it is because I wasn't going to put it at first but then decided to anyway. The #include "Laser.h" line of code references the header file where the class actually is.
Last edited on
Possibly you may want to look in to separating the commands, and passing a variable to the push_front.

In addition, it strikes me that you could try putting #include "World.h" under #include "Laser.h" - might help.
1
2
CLaser x;
lLaser.push_front(x);

This results in the same errors. Also, rearranging the #include statements didn't help. I actually spent quite some time messing with different things like this to see if it would yield different results but I still keep getting these same errors. Here is a more in-depth look at my code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Laser.h
#ifndef H_LASER
#define H_LASER

class CLaser {
public:
	CLaser();
	CLaser(float,float,float);
	~CLaser();
	void updateLaser();
private:
	float lasX, lasY, xVelocity;
};

#endif 

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
// Laser.cpp
#include "DarkGDK.h"
#include "Laser.h"

CLaser::CLaser() {
	// Default should not be used but lets give it values anyway
	lasX = 850;
	lasY = 300;
	xVelocity = 4;
}

CLaser::CLaser(float x, float y, float xVel) {
	lasX = x;
	lasY = y;
	xVelocity = xVel;
}

CLaser::~CLaser() {

}

void CLaser::updateLaser() {
	// Update position
	lasX -= xVelocity;

	// Draw the image
	dbSprite(25,lasX,lasY,25);
}

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
// World.h
#ifndef H_WORLD
#define H_WORLD
#include <list>
#include "time.h"
#include "Asteroid.h"
#include "Laser.h"

class CWorld {
public:
	CWorld();
	~CWorld();
	void worldUpdate();

private:
	std::list<CAsteroid> lAsteroid;
	std::list<CLaser> lLaser;
	int stageValue;
	clock_t stageTimer;
	clock_t laserTimer1, laserTimer2;
	clock_t sAsterTimer1, sAsterTimer2;
	clock_t mAsterTimer1, mAsterTimer2;
	clock_t lAsterTimer1, lAsterTimer2;
};

#endif 

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
// World.cpp
#include "DarkGDK.h"
#include <list>
#include "time.h"
#include "Asteroid.h"
#include "Laser.h"
#include "World.h"

using namespace std;

CWorld::CWorld() {
	laserTimer1 = clock() + 2 * CLOCKS_PER_SEC;;
}

CWorld::~CWorld() {

}

void CWorld::worldUpdate() {
	// Seed the generator
	srand(time(0));

	//----------------- Laser creation and handling -----------------
	if (laserTimer1 <= clock()) {
		CLaser x;
	 	lLaser.push_front(x);
	}
}

Those are exact duplicates, no line was left out. Not sure if that will help at all. Note that some things (like the seeding) don't yet do much and some things are still unfinished because these errors have halted my progress. I didn't want to continue until I could get this resolved.
The purpose of separating the commands is to see where the problem is happening, if it's on the push_front line or the initialization of the object, so which of those lines is it on?

Also, once you've determined which line it is, try
1
2
CLaser *x = new CLaser;
lLaser.push_front(x);

And change (in World.h):
std::list<CLaser> lLaser;
to:
std::list<CLaser*> lLaser;

This means, of course, that you're going to have to delete x; later on, once you've finished with it.
Last edited on
The line that is causing the errors is the push_front line (when I comment that line out, my errors go away). Also, I changed all the lines to what you suggested but I am still receiving the same errors. I tried commenting out the push_front command and then using a pop command (to see if that would result in error) and it did as well although the error was different. It seems that trying to use the list in any way results in errors, regardless if it is something that I am passing values to or not.

However, what exactly would the asterisks do to the code? Wouldn't that make x and the list a pointer to CLaser? What benefit does that give?

This is the error I got from the pop command:
1>World.obj : error LNK2019: unresolved external symbol __CrtDbgReportW referenced in function "public: class std::list<class CLaser *,class std::allocator<class CLaser *> >::_Const_iterator<1> & __thiscall std::list<class CLaser *,class std::allocator<class CLaser *> >::_Const_iterator<1>::operator--(void)" (??F?$_Const_iterator@$00@?$list@PAVCLaser@@V?$allocator@PAVCLaser@@@std@@@std@@QAEAAV012@XZ)
1>libcpmtd.lib(stdthrow.obj) : error LNK2001: unresolved external symbol __CrtDbgReportW
fatal error LNK1120: 1 unresolved externals
It makes x a pointer, and it makes the list a list of pointers. This allows you to dynamically create objects at runtime instead of being limited to pre-defining the number of objects that you create at compile time.

Give me a minute with your push_front. While I'm looking, have you tried a push_back instead? I personally don't like using push_front when it truly is a list, I only use push_front with deques and vectors.
I'm comparing your list to a vector that I used with an old program that I wrote for my brother to keep track of his D&D games' characters, and the syntax you're using is right, but...it's still giving an error. My best guess at this point is that having the list operator in a separate file from the declaration of the same could be effecting it, but I don't see how.
Push_back also results in the same error. I also already tried putting the declaration in the same file and it didn't change anything. If I don't manage to figure out a solution, I'll probably just move on and use a different method (like a linked list or something). However, I would really like a solution to this problem so I know what it is that is going wrong so that I could avoid it in the future.
Here, I'm putting relevant portions of the code that I'm comparing yours to in here; see if you glean anything from it that might resolve your issue. I, unfortunately, don't have a compiler with me right now so everything I'm suggesting is without the benefit of my being able to test it.

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
150
151
152
153
154
155
#include "harmless.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <list>
#include <stdlib.h>
#include <string>
#include <functional>
#include <algorithm>
#include "RollerMk3.h"

using namespace std;

class character {
protected:
	int statStam, statWill, statRef, statInt, statStr, statPercp, statAgil, statAware, _
                    ringVoid, ringAir, ringEarth, ringWater, ringFire;
	string charName;
	int setRing(int, int);
public:
	character(string, vector<int>&);
	~character(){};
	void printStats();
	friend class characterSet;
};

/************************/
/*Lots of functions here*/
/************************/
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();// I deleted the line under this because it's useless and long.
			++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, passes the stats, calls printStats(), and calls diceRoller().
character * newCharacter(){
	vector<int> stats;
	int temp;
	string name, statNames[9] = {"Void Ring", "Stamina", "Will", "Reflex", "Intelligence", "Strength", "Perception", "Agility", "Awareness"};
	cout << "Enter the character's:" << endl;
	cout << "Name$ ";
	cin >> name;
	for(int i = 0; i < 9; i++){
		cout << statNames[i] << "$ ";
		cin >> temp;
		stats.push_back(temp);
	}
	character *newChar = new character(name, stats);
	return newChar;
}


I'll see what I can figure out later tonight and tomorrow.
It makes x a pointer, and it makes the list a list of pointers. This allows you to dynamically create objects at runtime instead of being limited to pre-defining the number of objects that you create at compile time.
That's what the containers are for. The use of pointers make sense in polymorphism.
1
2
list<Object> l;
l.push_back( Object() );

The list is making a dynamic allocation of the object.

@LoneWolf155: you should use srand() only one time in the whole program. If you are reseting the seed, then you lose the randomness

About the link errors, I've got no clue http://forum.thegamecreators.com/?m=forum_view&t=122531&b=22
Take this line that I gave you:
CLaser *x = new CLaser;
and change it to:
CLaser *x = new CLaser();
Tell me if that helps.
Hmm, thanks for the find ne555, I actually didn't think it had anything to do with the GDK but I guess I was wrong. My problem seems to be similar to the one in the link you provided. My project will run when in release mode but not when in Debug mode. I will see if I am able to finish the product under these conditions. Thanks for the help everyone!
Topic archived. No new replies allowed.