Restart a game and reinstantiate a global object [duplicate] - c++

This question already has an answer here:
Restarting a game and reinstantiate objects
(1 answer)
Closed 9 years ago.
This is a very similar problem to a question i have already looked at, answered here - Restarting a game and reinstantiate objects .
I want exactly the same thing except my problem is slightly different in that the object i wish to reinstantiate is 'global' and is only ever created when the program first runs.
At present i create the new 'Player' after my #includes and before my function prototypes ...
#include "Player.h"
#include "Monster.h"
using namespace std;
string MonsterTypes[3] = {"Orc","Goblin","Dark Rider"};
//create a stack of 'monsters'
stack<Monster>MonsterList;
Player* NewPlayer = new Player();
int NewGame();
void SetupPlayer();
void SetupMonsters();
void MainGame();
void Combat();
int GetMonstersLeft();
Do i need to create an entire factory class just to create a single player? Obviously when i call the function 'setupPlayer' i could create the player object in there, but would i not then have to pass 'NewPlayer' to every other function, i was just wandering if there was a way to avoid doing that?

You can create a new player in SetupPlayer, and assign it to NewPlayer.
Since your global NewPlayer is a pointer to a Player object, you can simply create a new Player in its place every time you call SetupPlayer(), as follows:
Player* NewPlayer = NULL; // Initialized when calling SetupPlayer()
void SetupPlayer() {
delete NewPlayer; // Delete the previous player (if any)
NewPlayer = new Player();
}

You don't really need dynamic allocation. You can just declare an automatic variable like this:
Player player;
and then when you want to reset it you can use:
player = Player();
Always remember that dynamic allocation is expensive.
What I would probably do, instead, is to create a "factory" function:
Player make_player() {
Player ret;
// setup ret
return ret;
}
So that you can get rid of that global object. Don't worry about the performance of copying the object back when returning: copies are elided by a well-known optimization (return value optimization - RVO).

Related

Can I create a pointer to an object in the constructor of said object?

The goal is that every time I create an object of my Car class, a pointer of this object is then created and placed in the "car registry".
This is what I have:
class Car {
private:
string color = "blah blah";
string make = "blah blah";
string model = "blah blah";
public:
Car(CarRegisterManager* carRegisterManager) {
// This is where I want to "register" any object of this class with a pointer
// to reference of this created object inserted into the CarRegisterManager's vector or
// registered cars.
carRegisterManager->registerCar( /*pointer goes here*/ );
}
}
class CarRegisterManager {
private:
std::vector<Car> registeredCars_;
public:
void registerCar(Car* car) {
registeredCars_.push_back(car);
}
}
int main() {
CarRegisterManager carRegisterManager;
CarRegisterManager* p_carRegisterManager = &carRegisterManager;
Car hondaCivic1(p_carRegisterManager); // When this is created, I want a pointer to it registered.
}
As you can see, part of my solution was to upon creation of the CarRegisterManager to create a pointer to the manager object to include as a parameter in the constructor of any Car object, then having the constructor do something with that. I know I need to use a "this" or something to indicate that this created Car object needs a pointer created for it, and then this pointer is put into the CarRegisterManager's registerCar function.
I'm still struggling with the concept of using keywords new and this, if that is indeed what I would need to use here. I apologize if this is answered somewhere else. I legitimately searched for a while before posting this. I may not be using the correct key terms to set these things up.
Thanks.
You already know the answer, because you state it in your question:
I know I need to use a "this" or something to indicate that this created Car object needs a pointer created for it, and then this pointer is put into the CarRegisterManager's registerCar function.
You can use the literal this pointer, eg:
Car(CarRegisterManager* carRegisterManager) {
carRegisterManager->registerCar(this);
}

(C++) Pointers to Pointers of objects in different classes

everyone. I'm working on a final project for school and it's coming along great, but I've run into a bit of a problem with trying to use a pointer to a pointer. I'll do my best to explain the problem below:
So I have a class called Player that sort of looks like this:
class Player
{
Player();
int health;
void adjustHealth(int);
};
Player::Player()
{
health = 40;
}
void Player::adjustHealth(int adjust)
{
health += adjust;
}
I have another class called Shelter, that include "Player.h" and looks a little like this:
class Shelter
{
Shelter();
Player* player; // Create a pointer to Player class.
};
In the Shelter header file, I have the following in my default constructor:
Shelter::Shelter()
{
...Other code here.
player = new Player();
}
In the Shelter header file, I use this new player for things like:
player->adjustHealth(-1); // Subtract one health from the player.
Which works great.
The problem I'm facing is with creating another class called Church, that is in a separate header file and acts as a separate location in the game. I want Church to use the same player that Shelter does, so it has all of the same stats, etc, rather than creating a new player in Church (which is what I did in Shelter.h).
Right now, I have something like:
class Church
{
Church();
Shelter **cplayer; // This is supposed to be the pointer to the pointer.
};
The default constructor is where I'm having my problem. I want to use the same player from Shelter, not create a new player like I did in Shelter.
Church::Church
{
What should I do here?
}
I've tried a number of things, but I can't quite get it working. Eventually I want to be able to do something like this:
player->adjustHealth(-1); // Subtract one health from the player.
Only in Church, so that player's stats, like health, are adjusted no matter which location they are in.
I hope my question makes sense. If not, I can try to clarify better. Anyway, thanks in advance.
The problem I'm facing is with creating another class called Church, that is in a separate header file and acts as a separate location in the game. I want Church to use the same player that Shelter does, so it has all of the same stats, etc, rather than creating a new player in Church
This sounds like an ideal situation to use std::shared_ptr.
class Shelter
{
Shelter();
std::shared_ptr<Player> player; // Create a pointer to Player class.
// Provide a public accessor
public:
std::shared_Ptr<Player> getPlayer() const { return player; }
};
and
class Church
{
Church(std::shared_ptr<Player> pl) : player(pl) {}
std::shared_ptr<Player> player;
// You haven't explained in your post why you need this.
// Maybe you don't need it.
// Shelter** shelter;
};

Class value accessible from multiple files and functions c++

I apologize before-hand if this question has been asked before.
I put all my skills with google to use and still nothing so if this question has been answered before please just link the answer and I'll essentially end the question.
Anyway, with all that out of the way, my problem is that I have a class "Player.hpp" and a corresponding "Player.cpp" in which I have defined the location system for the "player" I can initialize the value fine (which is one of the functions of the class) but then when the player goes to the "play()" function (which holds the bones of the game and is located in another .cpp file) when I use the function to get the Location I stored there is nothing stored... any help would be appreciated.
If you don't understand what I'm asking please comment and I'll elaborate.
Code Below:
//Player.hpp
class player
{
public:
std::string getLocation();
void setLocation(std::string local);
void initLocation();
private:
std::string location;
};
//Player.cpp
void player::initLocation()
{
player::location = "B0";
return;
}
std::string player::getLocation()
{
return player::location;
}
void player::setLocation(std::string local)
{
player::location = local;
return;
}
//Main.cpp
//....
player plays;
plays.initLocation();
//....
//Game.cpp
//...
player plays;
std::string local = plays.getLocation(); //When I check there isn't a value that gets stored...
if(local.find(...)...)
Again, any help is appreciated and I apologize if a question like this has already been asked.
Edit:
I guess I should have clarified that I also want to change the value stored as the player progresses from room to room (as this is a zork style game I'm making)
Assuming that each instance of player could be in a separate location, you can resolve this issue by initializing the player's location with the default location in its constructor. This removes the need for initLocation(), and thus there is no need to call it from Main.cpp.
//Player.hpp
class player
{
public:
std::string getLocation();
void setLocation(std::string local);
player () : location("B0") {}
private:
std::string location;
};
It looks as if you omitted static in front of the class variable declaration:
class player
{
// ...
static std::string location;
};
... which then also requires a definition. Of course, the definition becomes a prime location to also initialize the value:
// Player.cpp
std:string player::location("B0");
making the initialization function unnecessary.

Why must my global variable be declared as a pointer?

When compiling my C++ program I receive no errors, however within unordered_map the hash function fails, attempting to mod by 0. (Line 345 of hashtable_policy.h of stl)
I've found a fix, but don't know why I'm having the problem to begin with.
My struct looks like this, (Sorry for the specific code.)
struct Player {
private:
Entity& entity = entityManager->create();
public:
Player() {
entity.addComponent(new PositionComponent(0, 0)); // Add component uses the unordered map.
}
};
Player playerOne; // Error perpetuates through constructor.
However, if I declare playerOne as a pointer, like so:
Player* playerOne;
and then call:
playerOne = new Player();
I do not have any issues.
I've been searching - with no success. What could I be doing wrong?
When you use a Player as a global, you've no idea if the entityManager (presumably another global) has been initialised yet - the order of initialisation of globals isn't defined.
When you use the pointer and initialise it with new (in main(), I presume), all the globals have been created by then, so the code works.
This highlights one of the reasons why global variables are a bad idea.

Vector Troubles in C++

I am currently working on a project that deals with a vector of objects of a People class. The program compiles and runs just fine, but when I use the debugger it dies when trying to do anything with the PersonWrangler object. I currently have 3 different classes, one for the person, a personwrangler which handles all of the people collectively, and a game class that handles the game input and output.
Edit: My basic question is to understand why it is dying when it calls outputPeople. Also I would like to understand why my program works exactly as it should unless I use the debugger. The outputPeople function works the way I intended that way.
Edit 2: The callstack has 3 bad calls which are:
std::vector >::begin(this=0xbaadf00d)
std::vector >::size(this=0xbaadf00d)
PersonWrangler::outputPeople(this=0xbaadf00d)
Relevant code:
class Game
{
public:
Game();
void gameLoop();
void menu();
void setStatus(bool inputStatus);
bool getStatus();
PersonWrangler* hal;
private:
bool status;
};
which calls outputPeople where it promptly dies from a baadf00d error.
void Game::menu()
{
hal->outputPeople();
}
where hal is an object of PersonWrangler type
class PersonWrangler
{
public:
PersonWrangler(int inputStartingNum);
void outputPeople();
vector<Person*> peopleVector;
vector<Person*>::iterator personIterator;
int totalPeople;
};
and the outputPeople function is defined as
void PersonWrangler::outputPeople()
{
int totalConnections = 0;
cout << " Total People:" << peopleVector.size() << endl;
for (unsigned int i = 0;i < peopleVector.size();i++)
{
sort(peopleVector[i]->connectionsVector.begin(),peopleVector[i]->connectionsVector.end());
peopleVector[i]->connectionsVector.erase( unique (peopleVector[i]->connectionsVector.begin(),peopleVector[i]->connectionsVector.end()),peopleVector[i]->connectionsVector.end());
peopleVector[i]->outputPerson();
totalConnections+=peopleVector[i]->connectionsVector.size();
}
cout << "Total connections:" << totalConnections/2 << endl;
}
Where hal is initialized
Game::Game()
{
PersonWrangler* hal = new PersonWrangler(inputStartingNum);
}
0xBAADFOOD is a magic number to alert you to the fact that you're dealing with uninitialized memory. From the stack trace, we see that this in PersonWrangler::outputPeople is invalid. Thus hal doesn't point to a valid PersonWrangler (that is, assuming frame 4 is a call to Game::menu). To resolve this sort of thing yourself, step through the code, starting at Game::Game(), examining Game::hal as you go, to see what might be going wrong.
In Game::Game, hal is a local variable that shadows Game::hal. When Game::Game exits, this hal goes out of scope and leaks memory, while Game::hal remains uninitialized. What you want is:
Game::Game()
{
hal = new PersonWrangler(inputStartingNum);
}
Debuggers fill uninitialized memory with magic numbers to make it easier to spot errors. In a production build, memory isn't filled with anything in particular; the content of uninitialized memory is undefined, and might hold valid values. This is why a production build might not fail when a debug build will.
Did you initialize hal to point to an actual PersonWrangler object?
Creating a pointer does not point it at an actual object unless you do it explicitly. You probably want to either pass a PersonWrangler to your Game at construction time, or have the Game constructor create a PersonWrangler using new. If you choose the latter, make sure to delete your PersonWrangler somewhere, probably in the Game deconstructor.