Intro:
So my final project for this semester is to create a dungeon game that the player inputs the choices he/she has to make on the terminal and the output is his/her current status (e.g. current health, shield, damage, current room, etc). The dungeon is made up of rooms (2-dimensional, so the player could go up, down, right, left depending on the map) and the rooms have objects in them, including Monsters, NPCs, Items. Player can choose to interact with the objects (fight monsters, buy from NPCs or pick up Items) or move to another room. The professor has given us the classes' header files, and we have to simply write the cpp files for it.
Classes, members, and methods (that has to do with the problem):
Room - it has private members Room* upRoom, downRoom, leftRoom, rightRoom int index vector<Object*> objects and it basically just a linked list but 2-dimensional. Every room has its own index and vector of object pointers (might point to Item, Monster or NPC). To access the index of the room, use getIndex() function that returns the index. To access the vector objects, use getObjects() function that returns the vector.
Object - the base and abstract class, it has a private member string name, and access name using getName function. There's also a virtual function that deals with different interactions with the Player based on different children classes of Object.
Item - derived from Object, its private members are int shield, health, attack that could increase the player's states when picked up.
Game Character - derived from Object, its private members are int currentHealth, maxHealth, attack, shield (basically the status of a character)
Monster - derived from Game Character.
NPC - derived from Game Character, it has private members string script vector<Item> items items are what the player could buy from the NPC.
Player - derived from Game Character, it has a private member Room* currentRoom a pointer that points to the player's current room. We can access currentRoom using getCurrentRoom() function.
Dungeon - the dungeon itself, it has private members Player player vector<Room> rooms that make up the whole game. It has functions like runDungeon createRoom() and createPlayer. The main.cpp only consists of runDungeon.
So back to the problem:
In the createRoom() function, I declared all the things I want in the map and pushed back to vector<Room> rooms, which is a private member of Dungeon. For example:
void Dungeon::createRoom(){
//create monster
Monster zombie("Zombie", 50, 50, 10); //the ints are just the states
//create commodities
Item beef("Beef", 69, 0, 30);
Item banana("Banana", 15, 0, 5);
Item deagle("Deagle", 0, 59, 0);
//create NPC
NPC vick("Vick", "Hello there! I'm Vick the monkey.", {banana, deagle});
//create rooms
Room zero(0, {&vick}); //contains index and vector<Object*> objects
Room one(1, {&beef, &zombie})
//linking rooms together
zero.setRightroom(&one);
one.setLeftroom(&zero);
//finally pushing back the rooms declared in this function to vector<Room> rooms
rooms.push_back(zero);
rooms.push_back(one);
}
There'a a function called displayRoom() which is to print out the room index and all the objects inside it.
void Dungeon::displayRoom(){
//print out current room index, this works fine
cout << player.getCurrentRoom()->getIndex << endl;
//print out current room's first object's name, this won't work
cout << player.getCurrentRoom()->getObjects().at(0) << endl;
//print out current room's vector<Object*> size, and it always print 0
cout << player.getCurrentRoom()->getObjects().size() << endl;
}
So my problem is that the vector full of object pointers disappears. Does declaring objects inside a function and pushing them back to a private member which other functions could access work? If not, is there a solution that might help? Sorry for my bad English, I hope you understand. :)
The variables you defined in createRoom have lifetimes which end when the function returns. So pointers to them (&vick, &beef, &zombie, &one, &zero) are dangling at that point, and any use of them is undefined behavior.
To create objects which live past the end of the function where they were created, they need to be put in some other object or container, or created with new or std::make_unique or std::make_shared. You'll also want to choose one object which acts as the "owner" of each object with longer lifetime, to make sure there's simple logic in charge of cleaning up the objects' lifetime ends. Probably the Dungeon is the owner of the Rooms, a Room is the owner of its objects, and an NPC is the owner of its stock for sale. (What about the player's inventory? Can a Monster have Items? Maybe GameCharacter should have some inventory ownership logic?)
The raw pointers you've mentioned suggest you're expected to use new and delete, even though that's harder and not a great design. If you must use raw pointers, then every class which acts as an owner of other objects via raw pointers must carefully follow the Rule Of Five. In this case, copying most objects doesn't make sense, so you could delete the copy constructor and copy assignment and have move-only classes.
But if you're allowed to, it would be much easier to express ownership of pointers using std::unique_ptr. For example, change the std::vector<Object*> objects; in Room to a std::vector<std::unique_ptr<Object>> objects;. Note this should only be the "owning" pointers. The "right room", etc. properties can stay as raw pointers, since it's really the Dungeon which owns all rooms. But you do want to make sure those raw pointers are pointing at the Room objects held by the Dungeon and not copies of them.
So I did a simplified version of my code using new and I think it worked correctly:
main.cpp
#include <iostream>
#include "object.h"
#include "room.h"
using namespace std;
class dungeon{
private:
vector<room> rooms;
public:
void createMap(){
room zero, one;
object* obj;
obj = new object("sword");
zero.addObjects(obj);
obj = new object("knife");
zero.addObjects(obj);
obj = new object("zombie");
one.addObjects(obj);
obj = new object("titan");
one.addObjects(obj);
rooms = {zero, one};
}
vector<room> getRooms(){
return rooms;
}
};
int main(){
dungeon Dungeon;
Dungeon.createMap();
cout << Dungeon.getRooms().at(0).getObjects().at(0)->getName() << endl;
}
room.h
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class room{
private:
int index;
vector<object*> objects;
public:
room(){}
room(int index, vector<object*> objects){
this->index = index;
this->objects = objects;
}
int getIndex(){
return index;
}
vector<object*> getObjects(){
return objects;
}
void setIndex(int index){
this->index = index;
}
void addObjects(object* obj){
objects.push_back(obj);
}
};
object.h
#include <iostream>
#include <string>
using namespace std;
class object{
private:
string name;
public:
object(string name){
this->name = name;
}
string getName(){
return name;
}
};
Related
So I am trying to make a game in c++ with SDL2 and ran into a little problem. In order to pick up a weapon from the ground, after I check if the player is next to the object and has clicked 'E' to pick it up in an inline function from a different namespace, I have to copy its address in a variable saved in the main class and delete the object from the ground so you can't re-pick it up. It seems that after I delete the object, the pointer from the main class gets the value from another object, not that I erased.
This is the main class .h file:
class GameScene : public Scene{
public:
GameScene();
void init(SDL_Renderer* &renderer, int sceneIdx); //initialize variables
void update(int &sceneIdx, double deltaTime, Vector2f screenSize); //update frame-by-frame
void graphics(SDL_Renderer* &renderer); //render objects
void clear(); //only called on exit
private:
std::vector<SDL_Texture*> textures = {}; //all the textures present in the game
std::vector<bool> movements{false, false, false, false}; //main character movements
std::vector<Weapon> droppedWeapons = {}; //dropped pickable weapons on the ground
std::vector<Weapon*> weapons = {nullptr, nullptr}; //slots for the primary and secondary weapon
std::vector<Bullet> bullets = {}; //ssaves all the fired bullets on the map until deletion
std::unordered_map<int, SDL_Rect> positionsAtlas = {}; //offsets in textures and render scales
Cube* cube = nullptr; //main character
int mode = 0; //0=nothing, 1=weapon --unused yet
bool currentWeapon = 0; //saves what weapon is being used(primary or secondary)
int mouseX, mouseY; //mouse position on screen
};
Here is the function call in the .cpp file:
WeaponActions::pickUpWeapons(cube, droppedWeapons, weapons, pickUp/*is E pressed*/, currentWeapon);
And the function in the WeaponActions namespace:
inline void pickUpWeapons(Cube* cube, std::vector<Weapon> &droppedWeapons, std::vector<Weapon*> &weapons, bool pickUp, bool ¤tWeapon)
{
for(unsigned int i=0;i<droppedWeapons.size();i++)
{
bool type = droppedWeapons[i].getType(); //type of weapon(primary or secondary)
if(weapons[type]==nullptr && pickUp) //there is empty space in inventory
{
if(Math::checkCollision(cube->getPos(), cube->getScale(), droppedWeapons[i].getPos(), droppedWeapons[i].getScale())) //check if cube is near weapon
{
weapons[type] = &droppedWeapons.at(i); //save address
droppedWeapons.erase(droppedWeapons.begin()+i); //delete element
currentWeapon = currentWeapon == type ? currentWeapon : type; //change current weapon if necessary
i--;
}
}
}
}
The type element in the Weapon object represent if it is a primary(rifle) or a secondary(pistol) weapon.
What should I do beside creating another object to store the object the pointer is headed to?
Looks like you've got some confusion with memory and what should be a pointer. I'm looking specifically at how you store your weapons here:
std::vector<Weapon> droppedWeapons = {}; //dropped pickable weapons on the ground
std::vector<Weapon*> weapons = {nullptr, nullptr}; //slots for the primary and secondary weapon
When you pickup a weapon you are currently assigning the pointer to the memory location of the Weapon object in your vector, but then immediately removing that weapon! That's why you observed that it appears you equipped the wrong weapon. The weapon you picked up has gone, the std::vector has been resized and the next one has shunted down to fill it's place (std::vectors are required to be hold their elements in contiguous memory). This operation could also leave a dangling pointer e.g. if the weapon you tried to pick up was the last in the droppedWeapons vector your weapons pointer would end up pointing past the end of the vector.
Without changing too much of the rest of your code, you could change droppedWeapons to a vector of Weapon* (weapon pointers), rather than Weapon. Then when you want to pickup the weapon, assign the pointer to your picked up weapons list like so:
weapons[type] = droppedWeapons.at(i); // pass weapon pointer
Followed by removing the element from droppedWeapons as you are already.
Now you are working with pointers you will have to fill droppedWeapons by allocating them with new, and cleanup all your Weapon* at some point with delete.
Before making this change, it may also be a good idea to learn more about stack vs heap memory allocation in c++ if you aren't familiar with it already :)
I'm trying to create a function that creates pointers to instances of a player class.
This is because, at the start of my game, I want to be able to make as many player instances as I want.
This is to make the game 2-player, 4-player or 3-player and theoretically, an infinite number of players determined by the user's input.
The problem I'm facing is that if I make my function to make pointers like this:
edit: player is a user defined class that I made.
void createPointer()
{
player * player1 = new player("George");
}
The pointer will only be locally declared, resulting in a memory leak, because I can't reference the pointer player1, as it's deleted once the function createPointer() concludes.
I wouldn't be able to reference the players correctly, as shown above, as they're all named player1. Makes me think I should use templates in c++ to change the name of the variable each time a player is created.
As shown below, I couldn't delete the player instance at the end of the game:
void endGame()
{
//delete the object the pointer
//is pointing to in memory
delete player1;
//set the pointer to point to NULL
//as default, so can check if pointer is pointing
//to anything
player1 = NULL;
}
So I was just wondering if there was another approach I could take? I know of one solution which is to globally declare the pointers beforehand. i.e
player * player1 = NULL;
player * player2 = NULL;
player * player3 = NULL;
void createPointer()
{
player1 = new player("George");
}
However, this would mean I cannot create a variable number of players without declaring all of them beforehand, as shown in the above example.
Apologies if I am misunderstanding anything, I would highly appreciate any advice whatsoever.
If you really want to use raw pointers for your players, you can modify your createPointer function to return what it has created:
player* createPointer()
{
player* createdPlayer = new player("George");
// Do whatever you need for initialization!
return createdPlayer;
}
Then, in the code that wants to use such players, do something like:
//...
player* player1 = createPointer();
player* player2 = createPointer();
//...
Then, when you've done with the players, you can just delete each one...
delete player1;
delete player2;
A better solution (IMHO) would be to put whatever code you (eventually) have in createPointer into the constructor definition for the player class; then you can just use code like player *p1 = new player("Harold"); rather than calling a function each time you make a new player.
But, as mentioned in the comments, you would be better off using either std::vector or std::shared_ptr objects.
You probably need a container of player instances. The default container is std::vector.
Something like
std::vector<player> players;
players.emplace_back("George"); // Create the first player
players.emplace_back("Fred"); // Create the next player
// etc.
You can refer to players by their (0 based) position in players
players[0].do_stuff(); // George does stuff
You can loop over all the players
for (auto & player : players) {
player.take_turn(); // each player in turn does something
}
When players is destroyed, it automatically cleans up the player objects
If i understand you correctly,maybe there are two solutions to solve your problem.
Here the codes.
#include <string>
#include <iostream>
using namespace std;
class Player
{
public:
Player(string name) :m_name(name) {
cout << "player " << m_name << " is created\n";
}
~Player()
{
cout << "pluaer " << m_name << " is destoryed\n";
}
private:
string m_name;
};
//The first solution : return a pointer
Player* creatPlayer_1(const string& name)
{
return new Player(name);
}
//The second solution : pass a reference of the pointer as the argument
void createPlayer_2(Player*& pPlayer, const string& name)
{
pPlayer = new Player(name);
}
int main()
{
Player* pPlayer_one = creatPlayer_1("one");
Player* pPlayer_two = nullptr;
createPlayer_2(pPlayer_two, "two");
delete pPlayer_one;
delete pPlayer_two;
}
I have 3 classes, Player, Monster and Attack.
Class Player
{
public:
void addMonster(string line);
// ...
}
Class Monster
{
public:
void addAttack();
// ...
private:
vector <Attack> _attacks;
}
Now, addMonster() creates a new monster mn, and then has mn call its method addAttack() to fill the vector _attacks
void Player::addMonster(string line){
//...
Monster mn(line); //creates a new monster
while(condition){
mn.addAttack();
}
}
void Monster::addAttack(){
//...
Attack *att = gio->findAttack(ID) //takes the attack from another part of the program
_attacks.push_back(*att);
}
and it seems to work, if I check the contents of _attacks while inside addAttack(), it is pushing the correct elements in, the size of _attacks changes and evreything,
but when the program returns to addMonster(), the _attacks vector of mn is still (or again) empty, as if it had not called the method at all.
Why?
it's as if the object that gets modified is just a copy of the one calling the method, so the original one is not affected, but then how am I supposed to change that vector of that specific object?
When you create the *att pointer in your addAtack you created it on the stack. Stack variables are deleted when their original function ends and so att is deleted at the and of add attack. One possible workaround for this is to create att on the heap, using the keyword new.
I have two classes, PersonnelLists and Employee. I create an instance of PersonnelLists in my main, like so:
int main() {
PersonnelLists example; //Make a personnel list
...
}
PersonnelLists uses a constructor with member initialisation of a list of employees, the number of employees, and the size of the array:
PersonnelLists::PersonnelLists(): List(new Employee[SIZE]), numEmployees(0), arraySize(SIZE){
}
This results in some null empty employees being created (I think?):
Employee::Employee(): employeeNumber(0), name(NULL), department(NULL) {
}
It is at this line that I get an invalid null pointer error.
I am new with C++, fresh off the boat from Java programming. I'm still a novice with pointers, so I'm not quite sure what I'm doing wrong here.
UPDATE:
As requested, here is the class definition of Employee:
#include <iostream>
class Employee {
public:
Employee(); //constructor
Employee(std::string name, std::string deparment);
void Print() const; //Print this employee's details
void setEmployeeNo(int employeeNum);
private:
int employeeNumber;
std::string name;
std::string department;
};
In Java, new Employee[SIZE] creates an array of null references.
In C++, new Employee[SIZE] creates an array of default-constructed instances of Employee. Your default constructor tries to set name and department to NULL. Attempting to initialize a std::string to NULL would give the error you describe.
There's no "null" string in C++, but you could default-construct name and department, which would set them to empty strings:
Employee::Employee(): employeeNumber(0), name(), department() {
Finally, if List can contain a variable number of elements, I would recommend that you use std::vector<Employee> (which is similar to ArrayList<Employee> in Java).
If name and department are std::strings (or a similar string type), then initializing them with NULL (a null character pointer) is invalid.
If I guessed right, you should default-initialize them instead, as:
Employee::Employee(): employeeNumber(0), name(), department() {
}
But we really can't tell without seeing the class definition of Employee.
As others have pointed out, you should use a std::vector instead of an array. That allows you to only
have valid Employee objects in your "list".
I don't know what the actual definitions of your classes are, so it's kind of hard to identify your problem.
But an option in modern C++ of doing that is to use a std::vector<Employee> data member inside PersonnelList class. std::vector can grow dynamically at runtime, using its push_back() method, e.g.
#include <vector> // for std::vector
class Employee
{
....
};
class PersonnelList
{
public:
PersonnelList()
{
// Nothing to do - vector is initialized empty
}
// Get current employee count
size_t Count() const
{
return m_employees.size();
}
// Add a new employee to the personnel
void AddEmployee(const Employee& newEmployee)
{
m_employees.push_back(newEmployee);
}
private:
std::vector<Employee> m_employees;
};
No need to use raw pointers or something similar: robust RAII STL container classes make your code simpler.
I am relatively new to C++ programming, but am a C programmer of 10 years so am more comfortable with pointers to objects than I am with references to objects.
I'm writing a Solitaire game - is this design unsafe? Is there a better way?
Anyway, I have a class SolitaireGame:
class SolitaireGame:
{
public:
SolitaireGame( int numsuits = 1 );
private:
Deck * _deck;
vector<Card> _shoe;
};
The Deck is defined thus:
class Deck:
{
public:
Deck::Deck( vector<Card>& shoe );
~Deck();
int DealsLeft() const { return deals_left; }
Card * PullCard();
private:
int deals_left;
int num_each_deal;
deque<Card *> _cards;
};
The Deck constructor, takes a reference to a vector of Card objects ( the shoe, normally 104 cards ) and pushes a pointer to each card onto it's own deque of pointers.
Deck::Deck( vector<Card>& shoe )
{
vector<Card>::iterator iter = shoe.begin();
while( iter != shoe.end() )
{
_cards.push_front( &(*iter) );
iter++;
}
}
}
The shoe is created in the SolitaireGame constructor. Once this vector of dynamically created Card objects has been created - I then pass a reference to this vector to the constructor.
SolitaireGame::SolitaireGame( int numsuits ):_numsuits(numsuits )
{
Card * c;
vector<Card> _shoe;
for( int i = 0; i < NUM_CARDS_IN_SHOE; i++ )
{
c = new Card();
_shoe.push_back( *c );
}
_deck = new Deck( _shoe );
}
My idea was that the shoe would be the container for the actual memory for the Card objects and the Deck and Columns just handle pointers to those Card objects.
Just taking this snippet of code, you leak dynamically created cards.
Card * c;
vector<Card> _shoe;
for( int i = 0; i < NUM_CARDS_IN_SHOE; i++ )
{
c = new Card();
_shoe.push_back( *c );
}
_shoe.push_back( *c ) adds a copy of the Card object pointed to by c to the vector of Cards. You then fail to delete the original Card as created in the line before.
Allocating a vector of NUM_CARDS_IN_SHOE Cards can much more simply be achieved like this:
std::vector<Card> _shoe( NUM_CARDS_IN_SHOE );
Looking at your card structure, it looks like you have (or nearly have) strict ownership between objects so I don't think that you need to dynamically create your Cards.
Note that your local variable _shoe is shadowing the class variable _shoe. This probably isn't what you want as the local _shoe which you pass to the Deck constructor will go out of scope at the end of the constructor.
If you reorder you variables in SolitaireGame, you can probably do something like this:
class SolitaireGame:
{
public:
SolitaireGame( int numsuits = 1 );
private:
vector<Card> _shoe;
Deck _deck;
};
SolitaireGame::SolitaireGame( int numsuits )
: _shoe(NUM_CARDS_IN_SHOE)
, _deck(_shoe)
{
}
I've changed _deck from being a pointer. I'm using the fact that member variables are constructed in the order declared in the class definition, so _shoe will be fully constructed before it is passed as a reference to the constructor for _deck. The advantage of this is that I have eliminated the need to dynamically allocate _deck. With no uses of new, I know that I can't have any missed calls to delete as nothing needs to be deallocated explicitly.
You are right that you can store pointers to the Cards in _shoe in your _deck without any memory management issues, but note that you must not add or remove any of the Cards in the _shoe during the lifetime of the game otherwise you will invalidate all of the pointers in _deck.
I think there're two mistakes:
When you do _shoe.push_back( *c );, you're creating a copy of the Card object, so the memory reserved to c will never be freed. Btw, you should always check that for each new exists a complementary delete. Where is your delete?
In your Deck constructor you're saving pointers to objects that reside in the stack (vector<Card> _shoe;), so as soon as the SolitaireGame constructor ends, they will be deleted and your pointers will be invalid. EDIT: I see you've got another _shoe in your class, so it's not necessary to declare another _shoe local variable, in fact just by not declaring it you will solve this issue.
I hope this helps you a bit.
Initial thoughts:
In class SolitaireGame, you declare _shoe as:
vector<Card> _shoe;
but in the constructor you push heap objects on to it like this:
c = new Card();
_shoe.push_back( *c );
So, you need to declare it like this:
vector<Card*> _shoe;
You don't initialise variables in constructors, such as deals_left and num_each_deal in class Deck. I'll assume you left it out to not clutter up the code, but it's a good idea.
Class SolitaireGame creates and owns the Deck objects. It also has a Deck with pointers to SolitaireGame's Card objects. The ownership here is unclear - who deleted them? While having pointers to objects in multiple containers will work, it can make debugging more difficult, as there's scope for multiple deletion, using after it's been deleted, leaks etc. Perhaps the design could be simplified. Perhaps have Deck own the Card objects initially, and when they're removed, they get put into the vector in SolitaireGame, and don't exist in both at the same time.
In the constructor for SolitaireGame, you declare another vector of cards, which shadows the one declare in the class declaration. When you push the Card objects onto it, they'll not get pushed to the correct vector, which will go out of scope at the end of the constructor, and your class member will be empty. Just get rid of it from the constructor.
Anyway, I need a cup of tea. After that I'll take another look and see if I can suggest anything else.
I don't think the new keyword should appear anywhere in the code of these classes, and I don't see why you'd go through the trouble to share cards through pointers. Storing addresses of items held in a vector is recipe for disaster - you need to guarantee that there will be no modifications to the vector after you take the addresses, as it tends to move things around in memory without telling you.
Assuming a Card object doesn't store anything besides one or two ints, it would be a lot simpler to work with copies and values.
_deck = new Deck( _shoe );
Again, I don't see a slightest reason to increase complexity of the program by allocating an object containing two ints and a deque dynamically.
If you are worried about cost of copying some of the larger classes you have (which I would estimate has zero impact on perceived performance here), then simply don't copy them, and pass them around by const reference (if you don't need to mutate the instance), or non-const reference/pointer otherwise.
This program will leak memory , Want to find out why ? or how ?
push_back
Do remember this call do not insert your supplied element , But creates a copy of it for own use. Read this for detail
So
Card *c = new Card(); // This is on heap , Need explicit release by user
If you change it to
Card c; // This is on stack, will be release with stack unwinding
Copy below program and execute it, {I simply added logging}, try with both option, above
#include<iostream>
#include <vector>
#include <deque>
using namespace std;
const int NUM_CARDS_IN_SHOE=120;
class Card
{
public:
Card()
{
++ctr;
cout<<"C'tor callend: "<<ctr<<" , time"<<endl;
}
~Card()
{
++dtr;
cout<<"D'tor called"<<dtr<<" , time, num still to release: "<<((ctr+cpy)-dtr)<<endl;
}
Card& operator=(const Card & rObj)
{
return *this;
}
Card (const Card& rObj)
{
++cpy;
cout<<"Cpy'tor called"<<cpy<<endl;
}
private:
static int ctr,dtr,rest,cpy;
};
int Card::ctr;
int Card::dtr;
int Card::rest;
int Card::cpy;
class Deck
{
public:
Deck::Deck( vector<Card>& shoe );
~Deck();
int DealsLeft() const { return deals_left; }
Card * PullCard();
private:
int deals_left;
int num_each_deal;
std::deque<Card *> _cards;
};
Deck::Deck( vector<Card>& shoe )
{
vector<Card>::iterator iter = shoe.begin();
while( iter != shoe.end() )
{
_cards.push_front( &(*iter) );
iter++;
}
}
class SolitaireGame
{
public:
SolitaireGame( int numsuits = 1 );
private:
Deck * _deck;
std::vector<Card> _shoe;
};
SolitaireGame::SolitaireGame( int numsuits )
{
Card * c;
vector<Card> _shoe;
for( int i = 0; i < numsuits; i++ )
{
c = new Card();
_shoe.push_back( *c );
}
_deck = new Deck( _shoe );
}
int main()
{
{
SolitaireGame obj(10);
}
int a;
cin>>a;
return 0;
}
Since such a game object always has its own deck you should consider making the Deck object a real member inside SolitairGame -- not just a pointer. This will make life-time management of the deck object much simpler. For example, you won't need a custom destructor anymore. Keep in mind that STL containers contain copies. If you write something like
myvector.push_back(*(new foo));
you have a memory leak.
In addition, storing pointers to elements of a vector is dangerous because the pointers (or iterators in general) might become invalid. For a vector this is the case when it needs to grow. An alternative is std::list which keeps iterators valid after insertion, deletion, etc.
Also, keep in mind that in C++ structs and classes usually get implicit copy constructors and assignment operators. Honor the rule of three. Either disallow copying and assignment or make sure that resources (including dynamically allocated memory) is properly managed.