I see some odd behaviour in the code below. My console is printing
0lo1lo
when in reality I am expecting
0Hel1lo
Node.cpp
std::vector<Node> Node::getChildren() {
return children;
}
void Node::setChildren(std::vector<Node> childrenNodes) {
children = childrenNodes;
}
void Node::addChild(Node child) {
children.push_back(child);
std::cout << child.getTitle();
}
std::string Node::getTitle() {
return title;
}
From Main function
Node root = Node("root");
root.addChild(Node("Hel"));
root.addChild(Node("lo"));
std::cout << "\n";
std::vector<Node> children = root.getChildren();
for (int i = 0; i < children.size(); i++) {
Node menuItem = children[i];
std::cout << i;
std::cout << menuItem.getTitle();
}
std::cout << "\n";
Does anybody have an idea why getChildren() appears to be getting a vector that is not accurately listing the first element I inserted?
You're using global variables to store instance data:
std::string title;
That means there's only one title in your program and if you ever change it, it changes for every class, function, etc. that accesses it.
Make it a non-static member variable of Node and your problem will go away.
Related
#include <iostream>
#include <string>
#include <vector>
class Enemy
{
private:
std::string rank = "Boss";
std::string rank2 = "Miniboss";
public:
std::string type;
std::string get_rank(){
return rank;
}
std::string get_rank2(){
return rank2;
}
};
int add_enemy(std::vector<Enemy>&enemies, Enemy enemy) // I wanna pass by reference because I want to modify the vector
{
for(size_t i; i < enemies.size(); i++) {
if(enemies.at(i).type == enemy.type){ // here I'm saying, if I add an enemy that's of the same type, I don't wanna add it anymore
return 1; // it returns an error, because they are the same type, so it shouldn't add it?
}
}
enemies.push_back(enemy);
}
int main()
{
Enemy enemy;
enemy.type = "Dragon";
std::cout << enemy.type << " is a " << enemy.get_rank() << std::endl;
Enemy nrone, nrtwo, nrthree, nrfour, nrfive;
// I want to add these and keep them in a vector
std::vector<Enemy> enemies;
nrone.type = "Orc";
nrtwo.type = "Goblin";
nrthree.type = "Troll";
nrfour.type = "Ogre";
nrfive.type = "Orc";
std::cout << nrfour.type << " is of rank " << nrfour.get_rank2() << std::endl;
enemies.push_back(nrone);
enemies.push_back(nrtwo);
enemies.push_back(nrthree);
enemies.push_back(nrfour);
enemies.push_back(nrfive);
std::cout << add_enemy(enemies, enemy) << std::endl;
return 0;
}
Hi, I am studying Classes & Objects in C++ right now, and I'm trying to achieve the following: create a vector of NPC monsters and add a bunch of monster types to the vector. However, if the monster/enemy is of the same type, I don't want to add it to the vector, but discard it.
In my case, I have two Orcs, so the vector should discard one of the orcs, but it doesn't, and instead if showing me a strange number on the screen.
I tried it this way and I still can't figure it out :( Any solutions?
So the reason that both Orcs are added is because by the time you run add_enemy, you've already added them. All the enemies should be using the add_enemy function instead of push_back:
int main()
{
Enemy enemy;
enemy.type = "Dragon";
std::cout << enemy.type << " is a " << enemy.get_rank() << std::endl;
Enemy nrone, nrtwo, nrthree, nrfour, nrfive;
// I want to add these and keep them in a vector
std::vector<Enemy> enemies;
nrone.type = "Orc";
nrtwo.type = "Goblin";
nrthree.type = "Troll";
nrfour.type = "Ogre";
nrfive.type = "Orc";
std::cout << nrfour.type << " is of rank " << nrfour.get_rank2() << std::endl;
enemies.push_back(nrone); //Add one Orc
enemies.push_back(nrtwo);
enemies.push_back(nrthree);
enemies.push_back(nrfour);
enemies.push_back(nrfive); //Add another Orc
std::cout << add_enemy(enemies, enemy) << std::endl; //The Orcs are already in enemies!
return 0;
}
The reason you're seeing a strange number on the screen is that if you DO successfully add an enemy, the function doesn't return anything:
int add_enemy(std::vector<Enemy>&enemies, Enemy enemy) // I wanna pass by reference because I want to modify the vector
{
for(size_t i; i < enemies.size(); i++) {
if(enemies.at(i).type == enemy.type){
return 1; // Return an error
}
}
enemies.push_back(enemy); //OK, so we added the enemy, but where's the return?
}
Your add_enemies function must return a value, since it is declared as type int.
P.S... consider using a range based loop to make things a little easier:
for(Enemy& existingEnemy: enemies) {
if(enemy.type == existingEnemy.type) {
return 1;
}
}
The main problem is that you are not initializing the loop variable (i) in your add_enemy function (so the loop may never run, or it may skip some elements). Also, that function must return a value (presumably, 0) if the loop ends.
Try this:
int add_enemy(std::vector<Enemy>& enemies, Enemy enemy) // I wanna pass by reference because I want to modify the vector
{
for (size_t i = 0; i < enemies.size(); i++) { /// You forgot to initialize "i"!
if (enemies.at(i).type == enemy.type) { // here I'm saying, if I add an enemy that's of the same type, I don't wanna add it anymore
return 1; // it returns an error, because they are the same type, so it shouldn't add it?
}
}
enemies.push_back(enemy);
return 0; // The function MUST return an int value!
}
The strange number is easily explained. In your function you fail to return anything in the case where you do add the enemy. Add a return value and the strange number will go away.
int add_enemy(std::vector<Enemy>&enemies, Enemy enemy)
{
for(size_t i = 0; i < enemies.size(); i++) {
if(enemies.at(i).type == enemy.type){
return 1;
}
}
enemies.push_back(enemy);
return 0; // added a return value
}
The second problem with two orcs is also easily explained. You didn't use your add_enemy function when you added the orcs, you just used the regular vector push_back method so both orcs got added to the vector. You only used your add_enemy method for the dragon.
Also you fail to initialise i in the loop. I didn't spot that but I've corrected the code above.
I'm trying to code an text-based adventure game builder. I have three classes: Room, Object, and my main class. In my Room class, I have a (private) vector of pointers of Objects: vector<Object*> objectsInRoom
This keeps track of all the Objects stored in each room. I have a function called objects() in the Room class that returns objectsInRooms for when I call that vector in my main class.
vector<Object*> Room::objects() { return objectsInRoom; }
In my main class, in my function pickUpObject(), I've created a vector of pointers of Objects called roomObject. I call objects() in the Room class and store the Objects in objectsInRoom (which is only accessed in the Room class) in roomObject (which is accessible in my function in main). I also have a vector of Objects called allObjects that stores all the items that I want to pick up from the room and carry around with me. It has a global scope.
I want to make it so that if I pick up an item in a particular room, I add the item to allObjects, delete the pointer to that element in roomObjects (and thus the pointer to that element in objectsInRooms in the Room class), and the item itself.
My pickUpObject function is: (Room* current just tells me what room I'm in and thus what Objects I have)
void pickUpObject(vector<Object>&allObjects, Room* current)
{
vector<Object*>roomObjects; int length; string name; char flag;
roomObjects = current->objects();
length = roomObjects.size();
bool repeat = true;
while (repeat)
{
if (length == 0)
{
cout << "There are no objects to pick up in " << current->name() << endl;
repeat = false;
}
else
{
cout << "There is a ";
for (int k = 0; k < roomObjects.size() - 1; k++)
{
cout << roomObjects[k]->getName();
if (length > 2)
cout << ", ";
}
if (length > 1)
cout << " and " << roomObjects[length - 1]->getName() << " here." << endl;
else
cout << roomObjects[length-1]->getName() << "." << endl;
cout << "What object do you want to pick up?" << endl;
cin >> name;
//this is where the deletion happens
for (int i = 0; i < length; i++)
if (name.compare(roomObjects[i]->getName()) == 0)
{
allObjects.push_back(*roomObjects[i]);
roomObjects.erase(roomObjects.begin() + i);
deleteVectorContent(roomObjects, i, i + 1);
}
cout << "roomObject size = " << roomObjects.size() << endl;
cout << "--------------------" << endl;
cout << "allObject size = " << allObjects.size() << endl;
for (int i = 0; i < allObjects.size(); i++)
cout << allObjects[i].getName() << endl;
for (int i = 0; i < roomObjects.size(); i++)
{
cout << roomObjects[i]->getName() << endl;
}
cout << "Do you want to pick up another object? (Y/N): ";
cin >> flag;
if (flag == 'N')
repeat = false;
}
}
}
I've looked up various posts on StackOverflow to try and resolve my dilemma. In main, I've created a method called deleteVectorContent to try and delete the pointer.
void deleteVectorContent(vector<Object*> objectVector, int start, int stop)
{
for (int k = start; k < stop; k++)
delete objectVector[k];
objectVector.clear();
}
I've also tried 'roomObjects.remove()' to remove the item itself from that room. Whenever I compile, however, my compiler also throws me an exception. Help would be greatly appreciated.
P.S. The link to this assignment is here. If you scroll down to the "Extra Credit for the Programming Assignment" and go to the first one marked "10 points," that is what I am working on. Thank you so much for the help!
Room::objects() is returning a copy of objectsInRoom, so any modifications that pickUpObject() makes to that returned vector will not be applied back to objectsInRoom. You would need to make Room::objects() return a reference to objectsInRoom instead, eg:
vector<Object*>& Room::objects()
{
return objectsInRoom;
}
void pickUpObject(vector<Object> &allObjects, Room* current)
{
vector<Object*> &roomObjects = current->objects();
...
}
Otherwise, don't provide direct access to objectsInRoom at all. Introduce new methods to Room to access/remove a given Object* from its objectsInRoom, eg:
int Room::numObjects()
{
return objectsInRoom.size();
}
Object* Room::getObject(int index)
{
return objectsInRoom[index];
}
Object* Room::takeObject(int index)
{
Object *obj = objectsInRoom[index];
objectsInRoom.erase(objectsInRoom.begin()+index);
return obj;
}
void pickUpObject(vector<Object> &allObjects, Room* current)
{
int length = current->numObjects();
...
for (int i = 0; i < length; ++i)
{
if (name == current->getObject(i)->getName())
{
Object *obj = current->takeObject(i);
allObjects.push_back(*obj);
delete obj;
break;
}
}
...
}
Note that allObjects is receiving copies of the actual Objects, not Object* pointers. The code you showed is leaking memory when you make a copy of *roomObjects[i] and then erase() the Object* at i without delete'ing the Object it is pointing at. If Object is so easily copyable, you can save yourself a lot of headaches by simply getting rid of all the Object* pointers and just use Object everywhere:
class Room
{
vector<Object> objectsInRoom;
...
};
int Room::numObjects()
{
return objectsInRoom.size();
}
Object& Room::getObject(int index)
{
return objectsInRoom[index];
}
Object Room::takeObject(int index)
{
Object obj = objectsInRoom[index];
objectsInRoom.erase(objectsInRoom.begin()+index);
return obj;
}
void pickUpObject(vector<Object> &allObjects, Room* current)
{
int length = current->numObjects();
...
for (int i = 0; i < length; ++i)
{
if (name == current->getObject(i)->getName())
{
allObjects.push_back(current->takeObject(i));
break;
}
}
....
}
Otherwise, don't mix Object with Object* like you are, use Object* everywhere.
If you have a fixed set of Objects for the game, I would create a global vector<Object> to hold them all, and then just pass around Object* pointers everywhere as needed. Then you don't have to worry about cleaning up memory manually at all:
vector<Object> allGameObjects;
// fill as needed...
void Room::addObject(Object *obj)
{
objectsInRoom.push_back(obj);
}
Object* Room::takeObject(int index)
{
Object *obj = objectsInRoom[index];
objectsInRoom.erase(objectsInRoom.begin()+index);
return obj;
}
void pickUpObject(vector<Object*> &allObjects, Room* current)
{
...
allObjects.push_back(current->takeObject(i));
...
}
If you absolutely need a vector that owns Object* pointers that have to be cleaned up before the vector is destroyed, consider using vector<unique_ptr<Object>> for that, let the compiler and STL handle the hard work for you. If you ever find yourself having to write something like deleteVectorContent(), rethink your design.
I am a hobby coder who is learning by trying to make a text-RPG game on the console. I am just trying to think about how to design my code right now, and I'm getting stuck on how the items and inventory classes will work together. I have the inventory class defined like so:
class Inventory {
private:
vector<Item*> items;
public:
Inventory() {
items.resize(10);
for (int i = 0; i < 10; ++i) {
items[i] = nullptr;//so I can still display an empty inventory
}
};
~Inventory() {
for (int i = 0; i < 10; ++i) {
delete items[i];
}
}
void AddItem(Item* item) {
for (int i = 0; i < items.size(); ++i) {
if (items[i] == nullptr) {//if the slot is empty
items[i] = item;
break;
}
}
}
void Show() const {
for (int i = 0; i < items.size(); ++i) {
cout << "Slot " << i + 1 << ": ";
if (items[i] == nullptr) {
cout << "<Empty Slot>" << endl;
} else {
cout << "<" << items[i]->GetName() << ">" << endl;
}
}
}
};
Eventually I'm planning on having enemies dropping loot when they die, so I'll need to create items using new and then transfer them into the player's inventory. My question is, should I just learn about smart pointers and use them, or is the way I've called delete here okay or completely stupid? Or should I be thinking about this code structure differently? Thanks for answering, if you do! I really appreciate it.
The correct method would be to use iterators. Don't pass pointer of 'Item' in
void AddItem(Item* item) method.
You should create an iterator of 'Item' class and pass this iterator to "AddItem" method. Similarly create another method "RemoveItem" that returns an iterator of 'Item' that can be sent to Player's "CollectMoney" method.
If you don't want to use iterators, you can use "Item * item" as well but you have to call a method "RemoveItem" to get the reference of the "Item" so you can pass it to Player. Since the Items are not created inside the class, they should not be deleted in the class so remove the destructor.
PS use this constructor -> Inventory() {items.resize(10,nullptr);}
I have made a queue class and I have a queue and I want to reverse it,however when I implement the function it doesn't display anything.
Here's it
void reverse(Queue <T> &queue) {
if(!queue.empty())
{
int temp=queue.queue_front;
queue.pop(queue.queue_front);
reverse(queue);
queue.push(temp);
}
}
The pop function I'm using requires a value,that's why there is queue.queue_front.I'm trying to do it with a recursion.Here's my print function
void display() {
for(int current = queue_front+1; current < queue_length; current++)
{
cout << "[" << current << "]=" << queue_array [current] << " ";
}
}
Now that's what I'm doing in the main function
Queue <int>queue1(10);
queue1.push(16);
queue1.push(14);
queue1.push(6);
queue1.push(60);
queue1.reverse(queue1);
queue1.display();
Here's the pop function
void pop(T& item) {
if (empty()) {
cout << "The Queue is empty!";
exit(1);
}
else {
queue_front = (queue_front + 1) % queue_size;
item = queue_array[queue_front];
queue_length--;
}
}
It doesn't display anything.Thanks.
You're testing with a queue of integers, which hides quite a few bugs.
You should have tested with a Queue<std::string>.
First, here:
int temp=queue.queue_front;
you're saving an index, not an element.
What you intend must be
T temp = queue.queue_array[queue.queue_front];
but there's no reason to mess with member variables (see below).
Here,
queue.pop(queue.queue_front);
you're passing a reference to the queue's member to pop.
The parameter to pop is where the top element is stored after it's popped.
In other words, after that line, queue.queue_front will be the element that was at the front of the queue, not the index of the new front of the queue.
This would probably work:
void reverse(Queue <T> &queue) {
if(!queue.empty())
{
T temp;
queue.pop(temp);
reverse(queue);
queue.push(temp);
}
}
I'm getting a segfault when I run this code and I'm not sure why. Commenting out a particular line (marked below) removes the segfault, which led me to believe that the recursive use of the iterator "i" may have been causing trouble, but even after changing it to a pointer I get a segfault.
void executeCommands(string inputstream, linklist<linklist<transform> > trsMetastack)
{
int * i=new int;
(*i) = 0;
while((*i)<inputstream.length())
{
string command = getCommand((*i),inputstream);
string cmd = getArguments(command,0);
//cout << getArguments(command,0) << " " << endl;
if (cmd=="translate")
{
transform trs;
trs.type=1;
trs.arguments[0]=getValue(getArguments(command,2));
trs.arguments[1]=getValue(getArguments(command,3));
((trsMetastack.top)->value).push(trs);
executeCommands(getArguments(command,1),trsMetastack);
}
if (cmd=="group")
{
//make a NEW TRANSFORMS STACK, set CURRENT stack to that one
linklist<transform> transformStack;
trsMetastack.push(transformStack);
//cout << "|" << getAllArguments(command) << "|" << endl;
executeCommands(getAllArguments(command),trsMetastack); // COMMENTING THIS LINE OUT removes the segfault
}
if (cmd=="line")
{ //POP transforms off of the whole stack/metastack conglomeration and apply them.
while ((trsMetastack.isEmpty())==0)
{
while ((((trsMetastack.top)->value).isEmpty())==0) //this pops a single _stack_ in the metastack
{ transform tBA = ((trsMetastack.top)->value).pop();
cout << tBA.type << tBA.arguments[0] << tBA.arguments[1];
}
trsMetastack.pop();
}
}
"Metastack" is a linked list of linked lists that I have to send to the function during recursion, declared as such:
linklist<transform> transformStack;
linklist<linklist<transform> > trsMetastack;
trsMetastack.push(transformStack);
executeCommands(stdinstring,trsMetastack);
The "Getallarguments" function is just meant to extract a majority of a string given it, like so:
string getAllArguments(string expr) // Gets the whole string of arguments
{
expr = expr.replace(0,1," ");
int space = expr.find_first_of(" ",1);
return expr.substr(space+1,expr.length()-space-1);
}
And here is the linked list class definition.
template <class dataclass>
struct linkm {
dataclass value; //transform object, point object, string... you name it
linkm *next;
};
template <class dataclass>
class linklist
{
public:
linklist()
{top = NULL;}
~linklist()
{}
void push(dataclass num)
{
cout << "pushed";
linkm<dataclass> *temp = new linkm<dataclass>;
temp->value = num;
temp->next = top;
top = temp;
}
dataclass pop()
{
cout << "pop"<< endl;
//if (top == NULL) {return dataclass obj;}
linkm<dataclass> * temp;
temp = top;
dataclass value;
value = temp->value;
top = temp->next;
delete temp;
return value;
}
bool isEmpty()
{
if (top == NULL)
return 1;
return 0;
}
// private:
linkm<dataclass> *top;
};
Thanks for taking the time to read this. I know the problem is vague but I just spent the last hour trying to debug this with gdb, I honestly dunno what it could be.
It could be anything, but my wild guess is, ironically: stack overflow.
You might want to try passing your data structures around as references, e.g.:
void executeCommands(string &inputstream, linklist<linklist<transform> > &trsMetastack)
But as Vlad has pointed out, you might want to get familiar with gdb.