How to prevent a unordered_map of shared pointers from leaking? - c++

I am building a console application in wich I am only using smart pointers. I made the choice to only use smart pointers to learn when to use which smart pointer. In this application, I am trying to use a state pattern to switch between the different states. The base class is TurnState from this class all the other state-classes inherit.
In the gamecontroller, I have defined the current state. For switching between the states I want to use an unordered_map with an enum as key and the state class as value. But as soon as I wrote down std::unordered_map<TurnStateEnum, std::shared_ptr<TurnState>> _turn_states_map; inside the header I got some memory leaks.
To get rid of those memory leaks I tried to destroy them in the deconstructor like this:
GameController::~GameController()
{
for (std::unordered_map<TurnStateEnum, std::shared_ptr<TurnState>>::iterator iterator{ _turn_states_map.begin() }; iterator != _turn_states_map.end(); iterator++) {
iterator->second.reset();
_turn_states_map.erase(iterator);
}
_turn_states_map.clear();
}
But that did not work out either. I was able to solve it using raw pointers but that is not what I am trying to achieve. So my question is, how do I delete a map with shared_ptrs in the correct way?
All help will be appreciated.
Edit 1 - Minimal example
The Game Controller will be used for holding a shared_ptr to the current state and switching to the next one.
Below is the GameController header:
class GameController
{
public:
GameController();
~GameController();
void do_action(Socket& client, Player& player, std::string command);
void set_next_state(TurnStateEnum state);
private:
std::unordered_map<TurnStateEnum, std::shared_ptr<TurnState>> _turn_states_map;
std::shared_ptr<TurnState> _turn_state;
void initialize_turn_states_map();
};
Below is the GameController source:
GameController::GameController()
{
initialize_turn_states_map();
_turn_state = _turn_states_map.at(TurnStateEnum::SETUP);
}
GameController::~GameController()
{
for (std::unordered_map<TurnStateEnum, std::shared_ptr<TurnState>>::iterator iterator{ _turn_states_map.begin() }; iterator != _turn_states_map.end(); iterator++) {
iterator->second.reset();
_turn_states_map.erase(iterator);
}
_turn_states_map.clear();
}
void GameController::do_action(Socket& client, Player& player, std::string command)
{
_turn_state->do_turn(client, player, command);
}
void GameController::set_next_state(TurnStateEnum state)
{
_turn_state = _turn_states_map.at(state);
}
void GameController::initialize_turn_states_map()
{
_turn_states_map.insert(std::make_pair(TurnStateEnum::SETUP, std::make_shared<SetupState>(*this)));
}
The TurnState is the base class. This class should contain the current logic/behaviour of the application.
Below the TurnState header:
class GameController;
class TurnState
{
public:
TurnState(GameController& gameCtrl);
virtual ~TurnState();
void next_state(TurnStateEnum stateEnum);
virtual void do_turn(Socket& client, Player& player, std::string command) = 0;
protected:
GameController& _gameCtrl;
};
Below the TurnState source:
TurnState::TurnState(GameController& gameCtrl) : _gameCtrl ( gameCtrl )
{
}
TurnState::~TurnState()
{
}
void TurnState::next_state(TurnStateEnum stateEnum)
{
_gameCtrl.set_next_state(stateEnum);
}
Setup State does not have any other variables or methods than his base class and for now, the methods are empty.
Edit 2 - Minimal example v2
This might be a better minimal example. I created a console project and uploaded it to: https://ufile.io/ce79d

There are no leaks in your program. You are using std::shared_ptr correctly. There are no circular references to fix. Although the destructors were redundant, they were harmless.
You are just not using _CrtDumpMemoryLeaks() right. You are calling it before destructors for local objects in main are run. Naturally it will report memory allocated by these objects as leaks.
To fix:
int main(int argc, const char * argv[])
{
(
GameController gameCtrl = GameController();
gameCtrl.do_action("test");
}
_CrtDumpMemoryLeaks();
return 0;
}

Related

Pointer to a vector doesn't point

I have simplified the code as much as possible.
So I have two class:
class EntityManager
{
public:
std::shared_ptr<std::vector<Entity> > getEntities()
{
return std::make_shared<std::vector<Entity> >(m_entities);
}
private:
std::vector<Entity> m_entities{};
};
and
class System
{
public:
void loadEntities(std::shared_ptr<std::vector<Entity> > entities)
{
m_entities = entities;
}
private:
std::shared_ptr<std::vector<Entity> > m_entities;
};
Now basically I want the m_entities of System to point to the m_entities of EntityManager.
I did this:
system = System();
system.loadEntities(m_entityManager.getEntities());
But then I pushed back an element into the m_entities vector of EntityManager and this element wasn't added in the m_entities vector of System, which means my pointer doesn't point.
Where is my mistake?
Thanks!
Your problem is this line: return std::make_shared<std::vector<Entity> >(m_entities);
What is happening is that the shared_ptr manages a new std::vectory<Entity> container which is initialized as a copy of m_entities. Therefore, modifying the instance in the shared_ptr doesn't modify the data member in the EntityManager class and of course the shared_ptr won't see changes made to EntityManager::m_entities.
std::make_shared doesn't "make this thing shared"; it "makes a thing that will be shared".
So, you can't just make a shared pointer out of nowhere that points to something that already exists.
Your code dynamically allocates a std::vector, copy constructed from m_entities and managed by a std::shared_ptr. It's shorthand for this:
std::vector<Entity>* ptr_to_copy = new std::vector<Entity>(m_entities);
return std::shared_ptr(ptr_to_copy);
It's not clear what you're trying to do, from the code that (by your own admission) does not achieve that goal. But it seems unlikely that std::shared_ptr is appropriate here.
If it is, then make the vector dynamically-allocated and shared from the start; otherwise, just return a reference to the vector as it is.
Hack example of a pointer-free solution.
#include <string>
#include <iostream>
#include <vector>
//Hack-sample Entity class
class Entity
{
public:
Entity(const char * name): m_name(name)
{
}
void print() // this is stupid in real life. Prefer a << overload
{
std::cout << "Hi! I'm " << m_name << "!\n";
}
private:
std::string m_name;
};
class EntityManager
{
private:
std::vector<Entity> m_entities;
public:
// hide the fact that a vector is being used to store the entities.
// you can now swap out the vector for most standard containers without
// changing any code other than the using and the declaration of m_entities
using iterator = std::vector<Entity>::iterator;
EntityManager(): m_entities({"bob", "bill"})
// just pre-loading a few test entities
{
// RAII says you should load the entities from their source here
}
// get the first entity.
iterator begin()
{
return m_entities.begin();
}
// get the end of the entity list
iterator end()
{
return m_entities.end();
}
// adds an entity
void addEntity(const Entity & entity)
{
m_entities.push_back(entity);
}
// removes an entity
iterator removeEntity(iterator rem)
{
return m_entities.erase(rem);
}
};
class System
{
public:
// example method to show System working with EntityManager by printing all of the Entities
void printEntities()
{
for (EntityManager::iterator it = m_entityManager.begin();
it != m_entityManager.end();
++it)
{
it->print();
}
}
// example method to show System working with EntityManager by adding Entities
void addMoreEntities()
{
m_entityManager.addEntity(Entity("Ted \"Theodore\" Logan"));
m_entityManager.addEntity(Entity("Excellent!!!"));
}
private:
EntityManager m_entityManager ;
};
// sample test
int main()
{
System test;
test.printEntities();
test.addMoreEntities();
test.printEntities();
}
THIS HAS BEEN A HACK. THIS HAS ONLY BEEN A HACK.
If you want to do EntityManager right, see Writing your own STL Container for hints. If you want all of the bells and whistles, the job is fairly complicated. Depending on how you are using EntityManager and the complexity of the Entity management logic, you may be better off discarding EntityManager and just using the plain, old std::vector.
Addendum: What is meant by Resource Acquisition is Initialization (RAII)?

How to make a vector of *objects without being demoted to base class

In my class implementation, I have something like this:
base class
class swcWidget :
public swcRectangle
{
public:
swcWidget();
virtual ~swcWidget();
void update(float dt);
protected:
inline virtual void oPaintOnTop() { }
private:
};
derived class
class swcButton :
public swcWidget
,public swcText
{
public:
swcButton();
virtual ~swcButton();
static const int DEFAULT_SIZE = 20;
protected:
private:
void oPaintOnTop();
};
class swcApplication
{
public:
swcApplication(int argc, char *argv[]);
virtual ~swcApplication();
int run();
struct Controls
{
typedef std::vector<swcWidget*> vWidgets; //option 1
~Controls();
/////////////////////////////////
// M A I N P R O B L E M //
/////////////////////////////////
void add(swcWidget &&widgets); //most preferred option
//but gets demoted to base class.
void add(swcWidget *widgets); //second choice
//but should I make a copy of it?
//or just make a reference to it?
//and this one does what I wanted to.
//but still unsure on other things I don't know
void add(swcWidget *&&widgets); //this compiles fine (?)
//I don't know what kind of disaster I can make into this, but still does not do what I wanted.
inline vWidgets &getWidgets() {
return widgets;
}
private:
vWidgets widgets;
};
Controls controls;
};
I know some working option like this:
making the
swcApplication::Controls::widgets
as type of
std::vector<std::shared_ptr<swcWidget>>
but my code will bind into std::shared_ptr and I cannot make simple syntax like this:
swcButton btn;
app.controls.add(std::move(btn));
Example usage:
main.cpp
int main(int argc, char *argv[])
{
swcApplication app(argc, argv);
app.windows.create(640, 480);
if (font->load("fonts\\georgia.fnt") != BMfont_Status::BMF_NO_ERROR)
{
puts("failed to load \"georgia.fnt\"");
}
{
swcButton btn;
btn.setPosition(100, 100);
btn.setFont(font);
btn.text = "Ey!";
app.controls.add(std::move(&btn));
// btn.text = "Oy!";
}
return app.run();
}
Update:
Here's the temporary definition of swcApplication::Controls::add() although it may still vary
void swcApplication::Controls::add(swcWidget &&widget)
{
widgets.push_back(std::move(widget));
}
If a class is moveable, then it will in turn move it's members one by one. For this to be efficient, these members must either be small POD's or must be allocated on the heap. You must add this functionality, not forget to move any member, and object slicing is a concern to watch out for.
Given the class is non-trivial, you have the most efficient move construct available when you just use a pointer directly (at the cost of heap allocation time of course). No slicing is possible, and no member can be forgotten to be moved, since you move the whole object in one go. The one hurdle to watch out for is to keep track of who owns the pointers - you'd better set it in stone, but if that's done then there are no issues anymore.
The move semantics are wonderful, but if your classes are somewhat involved I think pointers in this case are easier / more efficient to work with. I'd thus stick with the pointer variant, and make sure your collection will own the pointers (and release them again via RAII) - make liberal use of comment in your public interface saying so. You can do this by storing some form of smart pointer (hint: be careful with unique_ptr's!), or (less safe) make and always use a Clear() member that delete's all pointers before clear()'ing the collection.
EDIT
Whet you define your widgets member to be of type vector, then example code could be:
To class swcApplication add:
void swcApplication::Controls::ClearWidgets() {
for (auto& nextWidget: widgets) {
delete nextWidget;
}
widgets.clear();
}
Don't forget to call ClearWidgets at the appropriate times (like in your destructor).
Adding widgets can be done with:
// Note: any passed widget will not be owned by you anymore!
template <typename Widget>
void swcApplication::Controls::add(Widget*& widget) {
widgets.push_back(widget);
widget = nullptr;
}
From now on you can add widgets like
swcButton* btn = new swcButton;
app.controls.add(btn);
// btn is now owned by app.controls, and should be set
// to nullptr for you to prevent misuse like deleting it
Using a smart pointer here should make it more safe, though storing unique_ptr's makes accessing them a bit error-prone (watch out for grabbing ownership back from the container when accessing them), and a shared_ptr gives overhead which might be unneeded here.

Calling virtual method of a derived class causes segfaults

I'm trying to make a chess program, but I want to be able to implement different AIs in it. Thus I made a abstract AIgeneric class and the derived class AIrandom off of AIgeneric. Then in my chessAI interface, I create a list of the the AIs, and try to call their getNextMove function and run into a segfault. The code is as below:
class AIgeneric {
public:
virtual int getNextMove(int*, const int &) = 0;
}
class AIrandom : public AIgeneric {
public:
AIrandom();
virtual int getNextMove(int*, const int &);
}
class chessAI {
public:
chessAI();
~chessAI();
void setAI();
int getNextMove(int*, const int &);
private:
vector<AIgeneric*> AIlist;
vector<string> names;
int selectedAI;
};
chessAI::chessAI () {
AIrandom randomAI;
AIlist.push_back(&randomAI);
names.push_back("Random AI");
selectedAI = -1;
}
int chessAI::getNextMove(int * board, const int & color) {
return AIlist[selectedAI]->getNextMove(board, color); //segfault on this line
}
It'd be great if anyone could help me on this problem!
Edit: I do set selectedAI to 0 before calling getNextMove.
In this code:
chessAI::chessAI () {
AIrandom randomAI;
AIlist.push_back(&randomAI);
names.push_back("Random AI");
selectedAI = -1;
}
You store a pointer to a local variable into your vector. After the constructor returns that pointer is no longer valid.
Remember that all local variables are stored on the stack, and the stack is reused in other functions. So when you use the pointer in the vector, it now points to some other functions memory and not the one object you declared.
This can be solved in three ways:
Allocate the object on the heap:
AIlist.push_back(new AIRandom);
Not using pointers at all.
Use smart pointers, such as std::unique_ptr.
You call selectedAI = -1; and then AIlist[selectedAI]->.... What do you expect AIlist[-1] to be, other than undefined behavior?
I expect this is because AIlist[selectedAI] is out of bounds. You can confirm this by replacing it with AIlist.at(selectedAI). Keep in mind that this index is -1 immediately after the constructor...

Trying to store objects in a vector

I'm quite new to C++ and I am trying to store objects inside a std::vector like this:
Event.h:
//event.h
class Event
{
public:
Event();
Event(std::string name);
~Event();
void addVisitor(Visitor visitor);
private:
std::vector<Visitor> m_visitors;
};
Event.cpp:
//event.cpp
Event::Event() :
m_name("Unnamed Event")
{
}
Event::Event(std::string name) :
m_name(name)
{
}
void Event::addVisitor(Visitor visitor)
{
this->m_visitors.push_back(visitor);
}
void Event::listVisitors()
{
std::vector<Visitor>::iterator it;
for(it = this->m_visitors.begin();it != this->m_visitors.end(); ++it)
{
std::cout << it->getName() << std::endl;
}
}
Visitor.h:
//visitor.h
class Visitor
{
public:
Visitor();
Visitor(std::string name);
~Visitor();
std::string getName() const;
void listVisitors();
private:
std::string m_name;
};
Visitor.cpp:
//visitor.cpp
Visitor::Visitor() :
m_name("John Doe")
{
}
Visitor::Visitor(std::string name) :
m_name(name)
{
}
std::string Visitor::getName() const
{
return m_name;
}
main.cpp:
//main.cpp
int main()
{
Event *e1 = new Event("Whatever");
Visitor *v1 = new Visitor("Dummy1");
Visitor *v2 = new Visitor("Dummy2");
e1->addVisitor(*v1);
e1->addVisitor(*v2);
}
If I do it like this I would have to add a copy constructor which would make a deep copy so the object gets copied properly into the vector. I'm looking for a way around it by only storing pointers to the objects in a vector.
I already tried it with std::vector<std::unique_ptr<Visitor> > m_visitors, but then I got some errors when calling addVisitor in main.cpp. Of course I changed the declaration of the class members accordingly.
How would an appropriate declaration of the members and the member function look like to make it work?
Stylistically, if you are passing pointers, just accept pointers as the function arguments.
What's happening in the example code above is that the visitors are getting copied to become function arguments and the pointers you had are unreferenced by anything outside of the main function.
I can't speak to what the errors are that you're seeing as you didn't describe them but it probably has to do with incompatible types.
Just get rid of the news because for these data structures they're unnecessary.
int main()
{
Event e1("Whatever");
Visitor v1("Dummy1");
Visitor v2("Dummy2");
e1.addVisitor(v1);
e1.addVisitor(v2);
}
I would suggest that if you don't know how to use pointers you couldn't possibly want to store them instead (they're a hassle IMO to store in the vector when copying by value works just fine).
The compiler generated copy constructor should work just fine.
No manual deep copy required, because you are quite correctly using std::string, which supports RAII.
However, your main function has three memory leaks — there is no need to use new there anyway, so simply don't.
General rule of thumb:
If, at any time T, you're thinking of introducing more pointers into your code, then you're probably going in the wrong direction.

Memory problems

I have some singleton class (please, don't speak about singleton usage).
class InputSystem : boost::serialization::singleton<InputSystem>
{
private:
boost::shared_ptr<sf::Window> mInputWindow;
public:
InputSystem()
{
mInputWindow = boost::shared_ptr<sf::Window>( new sf::Window(someARgs) );
someMethod();
}
void someMethod()
{
mInputWindow->...() // Calling some methods of sf::Window class
// Everything is fine here
}
const sf::Input &Handle() const
{
return mInputWindow.get()->GetInput();
}
};
void main()
{
InputSystem::get_mutable_instance().Handle(); // Here is all members of InputSystem have invalid addresses in memory (0x000)
}
What's wrong could be there?
Here is all members of InputSystem have invalid addresses in memory (0x000)
Either someMethod() is zeroing your class data, or you have misdiagnosed the issue.
Change your main function to this:
InputSystem& inputSystem = InputSystem::get_mutable_instance();
inputSystem.Handle();
This puts the creation of the singleton and the first attempt to use it onto separate lines. Fire up your debugger and step through the code looking for the exact point that your singleton's data is corrupted.