map iterator erase not calling appropriate destructors - c++

gameObjects is a std::map<sf::String,VisibleGameObject*>, and results is a std::map<sf::String,VisibleGameObject*>::iterator. When this runs:
return gameObjects.erase(results);
I expected the destructor of VisibleGameObject to run, which is:
VisibleGameObject::~VisibleGameObject(){
m_pSceneManager->removeSprite(name);
}
never runs, until the class which holds gameObjects is destroyed, which then runs:
GameObjectManager::~GameObjectManager(){
std::for_each(gameObjects.begin(),gameObjects.end(),GameObjectDeallocator());
}
struct GameObjectDeallocator{
void operator()(const std::pair<sf::String,VisibleGameObject*>&p) const{
delete p.second;
}
};
then it does run. Why doesn't it run in the first case?
Using SFML 2.0
Thanks

erase removes the pointers from the container, but does not call delete.
Suggestion:
change your map to simply be:
std::map<sf::String,VisibleGameObject>
i.e. objects not pointers to them
or:
use a shared_ptr/unique_ptr (e.g. boost::shared_ptr or std::shared_ptr depending upon availability):
std::map<sf::String,std::shared_ptr<VisibleGameObject> >
which will call the destructor

calling erase() won't free the pointer as the implementation(map) doesn't know how the object pointed to was allocated ((example: should it call delete or free?) and more importantly it doesn't own the pointer i.e you don't transfer ownership to the container when storing pointers.
Use std::unique_ptr to wrap you pointer and then store it in the container by value. This will aid garbage collection and give you what you need.
using VisibileGameObjectPtr = std::unique_ptr<VisibleGameObject>;
std::map<sf::String,VisibleGameObjectPtr> gameObjects;
// memory will be automatically garbage collected when you erase this item.
gameObject["key"] = VisibileGameObjectPtr(new VisibleGameObject(..args..));

Related

Calling delete on std::stack of pointers

I have a std::stack which has some pointers inside:
std::stack<State*> m_states;
When I initialize my program, I call new to push an item onto the stack (it must be a pointer because I will use polymorphic types).
Is this the correct way of deleting with all the stuff?
Here is where I call new (GameState and MenuStatesare classes inherited fromState`):
m_states.push(new GameState());
m_states.push(new MenuState());
And this is what I have in the destructor of the whole App class:
while (!m_states.empty())
{
delete m_states.top(); // (*)
m_states.pop();
}
Should I only call (*), or do I need to pop() as well?
Should I only call (*) or do I need to pop as well?
Well, if you don't call pop() in the while loop, then how will that loop ever end? In other words, how will the condition, !m_states.empty() ever become false?
There are other container types (like std::vector) where you could just run through each member, deleting the pointed-to object, and then clear the container, but you can't do that with the std::stack container. That is to say, there is no [] operator for a stack – you can only access the top element.

Memory error while working with an Manager and an vector

I want to create a Manager that holds multiple objects and has to be used in order to actually create the objects.
The objects hold their information in a smart pointer.
this is how I implemented it:
struct Object
{
std::shared_ptr<int> number;
};
struct Manager
{
std::vector<Object> objects;
Object& createObject()
{
objects.emplace_back();
return objects.back();
}
};
int main()
{
Manager manager;
Object& object1 = manager.createObject();
object1.number = std::make_shared<int>(10);
for (Object& o : manager.objects)
{
std::cout << *o.number << std::endl;
}
}
If I execute this code I get my expected output: 10
but once I try to create multiple objects like this:
Manager manager;
Object& object1 = manager.createObject();
Object& object2 = manager.createObject();
object1.number = std::make_shared<int>(10);
object2.number = std::make_shared<int>(5);
for (Object& o : manager.objects)
{
std::cout << *o.number << std::endl;
}
I get an runtime error in the memory library at this function:
void _Decref()
{ // decrement use count
if (_MT_DECR(_Uses) == 0)
{ // destroy managed resource, decrement weak reference count
_Destroy();
_Decwref();
}
}
does anybody know why this is happening?
It is never a good idea to use vectors of class instances in conjunction with pointers or references to these class instances. Like Bo Persson already correctly answered, these pointers or references tend to become dangling due to the dynamic nature of a std::vector: when a std::vector grows, it often copies its items to a different memory position, leaving the already existing item references and pointers invalid (dangling).
You can easily avoid that by storing pointers to classes instead of the classes itself.
struct Manager
{
std::vector<std::unique_ptr<Object>> objects;
Object& createObject()
{
objects.emplace_back(std::make_unique<Object>());
return *objects.back().get();
}
};
Now std::vector may move the unique_ptr's around as it likes - the smart pointers content (raw pointers) and thus also the references never change (except if you willful change or delete them, of course)
Here's an illustration what happens when you use a vector of class instances.
The grey vertical stripes symbolize the memory - the real structure of memory and sizes are ignored here.
Step 1: You have a vector (symbolized by square brackets) holding a class instance as an item. The memory behind the vector is occupied (reality is a little different, but the image should suffice)
Step 2: You create a reference (or pointer) to your class instance. (green arrow)
Step 3: You add a second class instance to the vector. The vector has no room for its items, and thus have to move its content to another memory position. Your pointer/reference is broken! (red arrow)
And here's an illustration of the pointer solution:
Step 1: You have a vector again, but now it's a vector of smart pointers. It holds a smart pointer pointing (dark green arrow) to a class instance.
Step 2: You again create a reference (or pointer) to your class instance. (green arrow)
Step 3: You add a second pointer to a class instance to the vector. The vector has no room for its items, and thus has to move its content to another memory position. But this time only the smart pointers are moved, not the class instances itself! Class instance 1 stays at its place, smart pointer 1 still points to class instance 1, your reference stays intact, and everyone stays happy :)
Additionally: Apart from being a safe solution, using pointer vectors instead of instance vectors very often also has a performance benefit. unique_ptr are very small, nearly always much smaller than the objects they hold pointers to. And so, when std::vector has to copy its items to a different memory position, it has lot less work to do if these are only small smart pointers.
On top of that, there are some classes, which have expensive copy constructors (e.g. locking!). All of that can be avoided if the class instance is not copied at all.
When adding new elements to the vector, you risk that references to the old objects get invalidated.
See http://en.cppreference.com/w/cpp/container/vector/emplace_back where it says:
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated.
So after adding object2, the reference object1 might be invalid.

Memory Leaks without calling clear() on C++ STL container objects

Suppose that I have a class Foo defined as follows.
If I don't have bars.clear() in ~Foo(), will this result in memory leaks?
I was wondering about this because bars is an object field ( not a pointer field ) so when ~Foo() is called, the destructor of std::vector should be automatically called so I was wondering whether the destructor of std::vector will transparently call .clear() or not.
class Foo
{
private:
std::vector<Bar*> bars;//object field
...
};
Foo::~Foo
{
//bars.clear();
}
std::vector::clear() delete the objects within std::vector and change its std::vector::size() to zero. If you create std::vector, RAII will take care resource release process but you have to wait until reach the out of scope of the vector. If before going out of scope, you need to clean up your vector you can use std::vector::clear().
But in your special case you are keeping pointer to objects inside std::vector, so RAII do delete the pointer but ignores the objects pointing to the pointer. So you have to do your own clean up for the objects pointing to the pointer either before going out of scope and RAII become active or before calling std::vector::clear()
clear() just resets the vector to size 0. It does not delete anything, if the Bar* in the vector bars need to be deleted, you have to do it yourself.
If you hope to protect yourself against memory leaks by calling the clear() method, then I have to disappoint you. If you use a vector with pointers you need to do something like this:
std::vector<Bar*> bars;
bars.push_back(new Bar());
// some work with bars
// ....
// end of bars usage:
// (probably inside ~Foo() )
for(int i=0; i<bars.size(); i++) delete bars[i];
Depending on your level of experience and your specific use-case you might be better of using:
std::vector<Bar> bars;
If you want to know whether the std::vector<...>::clear() method is called from within the destructor of the vector, then the answer is: Maybe but not necessarily and it really doesn't matter anyway.
If you're really curious, you might be able to check, what a destructor of a container class does by looking at the header file for the vector container template. If and how much implementation details of std library objects are visible to the user is highly dependant on the system you're running with. At work I happen to work on Solaris 10 machines. The std lib on those machines is an implementation from Hewlett Packard anno 1994, where a lot of the actual code used by the vector template is still visible:
~vector ()
{
__destroy(__start, __finish);
__value_alloc_type va(__end_of_storage);
va.deallocate(__start,__end_of_storage.data()-__start);
}
void clear()
{
erase(begin(),end());
}
iterator erase (iterator first, iterator last)
{
iterator i = copy(last, end(), first);
iterator tmp = __finish;
__finish = __finish - (last - first);
__destroy(i, tmp);
return first;
}

Proper way to destroy a map that has pointer values

I am using std::map to map string values to MyType *. My map declaration looks like this:
map<string, MyType *> *my_map = new map<string, MyType>;
my_map is a private member variable of one of my classes. My problem is that I am unsure of how to destroy the map. When deleteing the map, I would also like to call delete on all of the MyType * contained in the map. Here is my current destructor:
my_map->erase(my_map->begin(), my_map->end());
delete my_map;
Will this delete the pointers contained in the map, or do I need to iterate through the map to delete each pointer before calling erase?
Pointers merely point. When using raw pointers, you need to know which part of your app owns the resources that the pointers point to. If they are owned by the map, you will need to iterate over the map and call delete on each pointer before the map is destroyed. But if the map just holds pointers to objects that are owned by other parts of your code, you don't need to do anything.
A safer solution is to use shared_ptr to manage object lifetime, which will ensure that the object gets deleted properly when the last shared_ptr is destroyed. You can store shared_ptrs inside the map and if no other shared_ptr instances reference the objects within the map, the objects will be destroyed when the map is destroyed, as desired.
If you use smart pointers instead of raw pointers, everything will be cleaned up for you automatically.
// header:
using MapType = std::map<std::string, std::shared_ptr<MyType>>;
shared_ptr<MapType> my_map;
// usage:
my_map.emplace("foo", std::make_shared<MyType>());
// destructor:
MyClass::~MyClass()
{
// nothing!
}
Will this delete the pointers contained in the map [...]?
No, given the code you have provided, you will leak every member of the map.
As a rule, for every new there must be a matching delete. You have a delete for the map, but none for the elements within.
The most correct solution to this problem is to not use dynamic allocation at all. Just store MyTypes directory, if possible:
map<string, MyType>
... and instead of dynamically allocating the map itself, store that automatically:
map<string,MyType> my_map;
If automatic storage duration is not possible for some reason, then use a smart pointer for the dynamic allocations. Given a C++11 compiler, use unique_ptr (or, rarely, shared_ptr or even weak_ptr) for the elements in the map:
map<string, unique_ptr<MyType>> my_map;
(Given a C++03 compiler, use the Boost equivalents thereof.) Then when my_map is destroyed, all the elements will be deleted.
Baring all of this, if you are in a situation where none of the above will work for you (I would by highly suspect), then you will need to iterate the map youself:
struct deleter
{
template <typename T> operator() (const T& rhs) const
{
delete rhs.second;
}
};
for_each (my_map->begin(), my_map->end(), deleter());
In C++11, this could be made a lambda, something along the line of:
for_each (my_map->begin(), my_map->end(), [](auto item) -> void
{
delete item.second;
});
In modern C++, just make your life easier and use pointers only if strictly required.
You started with this code:
map<string, MyType *> *my_map = new map<string, MyType>;
The first thing you can do is to consider using a std::map instance as data member, instead of a pointer to it.
Then, if MyType is not super-expensive to copy and its instances are only owned by the map, just consider a simple map from string to MyType (instead of MyType*):
// my_map data member - no pointers --> automatically deleted in class destructor
map<string, MyType> my_map;
If you really need a map containing pointers, consider using smart pointers, like std::shared_ptr (available in C++11/14) for shared ownership, or std::unique_ptr for unique non-shared ownership.
(If you target C++98/03, an option is to use boost::shared_ptr. Since there is no move semantics, you can't have unique_ptr, which is heavily based on the move semantics feature.)
e.g.:
// Map containing _smart_ pointers
// --> default destructor is fine (no need for custom delete code)
map<string, shared_ptr<MyType>> my_map;
As you can see, using value semantics (instead of raw pointers), or smart pointers, you can simplify your code and use the automatic destruction provided by C++.

Example to use shared_ptr?

Hi I asked a question today about How to insert different types of objects in the same vector array and my code in that question was
gate* G[1000];
G[0] = new ANDgate() ;
G[1] = new ORgate;
//gate is a class inherited by ANDgate and ORgate classes
class gate
{
.....
......
virtual void Run()
{ //A virtual function
}
};
class ANDgate :public gate
{.....
.......
void Run()
{
//AND version of Run
}
};
class ORgate :public gate
{.....
.......
void Run()
{
//OR version of Run
}
};
//Running the simulator using overloading concept
for(...;...;..)
{
G[i]->Run() ; //will run perfectly the right Run for the right Gate type
}
and I wanted to use vectors so someone wrote that I should do that :
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
but then he and many others suggested that I would better use Boost pointer containers
or shared_ptr. I have spent the last 3 hours reading about this topic, but the documentation seems pretty advanced to me . ****Can anyone give me a small code example of shared_ptr usage and why they suggested using shared_ptr. Also are there other types like ptr_vector, ptr_list and ptr_deque** **
Edit1: I have read a code example too that included:
typedef boost::shared_ptr<Foo> FooPtr;
.......
int main()
{
std::vector<FooPtr> foo_vector;
........
FooPtr foo_ptr( new Foo( 2 ) );
foo_vector.push_back( foo_ptr );
...........
}
And I don't understand the syntax!
Using a vector of shared_ptr removes the possibility of leaking memory because you forgot to walk the vector and call delete on each element. Let's walk through a slightly modified version of the example line-by-line.
typedef boost::shared_ptr<gate> gate_ptr;
Create an alias for the shared pointer type. This avoids the ugliness in the C++ language that results from typing std::vector<boost::shared_ptr<gate> > and forgetting the space between the closing greater-than signs.
std::vector<gate_ptr> vec;
Creates an empty vector of boost::shared_ptr<gate> objects.
gate_ptr ptr(new ANDgate);
Allocate a new ANDgate instance and store it into a shared_ptr. The reason for doing this separately is to prevent a problem that can occur if an operation throws. This isn't possible in this example. The Boost shared_ptr "Best Practices" explain why it is a best practice to allocate into a free-standing object instead of a temporary.
vec.push_back(ptr);
This creates a new shared pointer in the vector and copies ptr into it. The reference counting in the guts of shared_ptr ensures that the allocated object inside of ptr is safely transferred into the vector.
What is not explained is that the destructor for shared_ptr<gate> ensures that the allocated memory is deleted. This is where the memory leak is avoided. The destructor for std::vector<T> ensures that the destructor for T is called for every element stored in the vector. However, the destructor for a pointer (e.g., gate*) does not delete the memory that you had allocated. That is what you are trying to avoid by using shared_ptr or ptr_vector.
I will add that one of the important things about shared_ptr's is to only ever construct them with the following syntax:
shared_ptr<Type>(new Type(...));
This way, the "real" pointer to Type is anonymous to your scope, and held only by the shared pointer. Thus it will be impossible for you to accidentally use this "real" pointer. In other words, never do this:
Type* t_ptr = new Type(...);
shared_ptr<Type> t_sptr ptrT(t_ptr);
//t_ptr is still hanging around! Don't use it!
Although this will work, you now have a Type* pointer (t_ptr) in your function which lives outside the shared pointer. It's dangerous to use t_ptr anywhere, because you never know when the shared pointer which holds it may destruct it, and you'll segfault.
Same goes for pointers returned to you by other classes. If a class you didn't write hands you a pointer, it's generally not safe to just put it in a shared_ptr. Not unless you're sure that the class is no longer using that object. Because if you do put it in a shared_ptr, and it falls out of scope, the object will get freed when the class may still need it.
Learning to use smart pointers is in my opinion one of the most important steps to become a competent C++ programmer. As you know whenever you new an object at some point you want to delete it.
One issue that arise is that with exceptions it can be very hard to make sure a object is always released just once in all possible execution paths.
This is the reason for RAII: http://en.wikipedia.org/wiki/RAII
Making a helper class with purpose of making sure that an object always deleted once in all execution paths.
Example of a class like this is: std::auto_ptr
But sometimes you like to share objects with other. It should only be deleted when none uses it anymore.
In order to help with that reference counting strategies have been developed but you still need to remember addref and release ref manually. In essence this is the same problem as new/delete.
That's why boost has developed boost::shared_ptr, it's reference counting smart pointer so you can share objects and not leak memory unintentionally.
With the addition of C++ tr1 this is now added to the c++ standard as well but its named std::tr1::shared_ptr<>.
I recommend using the standard shared pointer if possible. ptr_list, ptr_dequeue and so are IIRC specialized containers for pointer types. I ignore them for now.
So we can start from your example:
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
The problem here is now that whenever G goes out scope we leak the 2 objects added to G. Let's rewrite it to use std::tr1::shared_ptr
// Remember to include <memory> for shared_ptr
// First do an alias for std::tr1::shared_ptr<gate> so we don't have to
// type that in every place. Call it gate_ptr. This is what typedef does.
typedef std::tr1::shared_ptr<gate> gate_ptr;
// gate_ptr is now our "smart" pointer. So let's make a vector out of it.
std::vector<gate_ptr> G;
// these smart_ptrs can't be implicitly created from gate* we have to be explicit about it
// gate_ptr (new ANDgate), it's a good thing:
G.push_back(gate_ptr (new ANDgate));
G.push_back(gate_ptr (new ORgate));
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
When G goes out of scope the memory is automatically reclaimed.
As an exercise which I plagued newcomers in my team with is asking them to write their own smart pointer class. Then after you are done discard the class immedietly and never use it again. Hopefully you acquired crucial knowledge on how a smart pointer works under the hood. There's no magic really.
The boost documentation provides a pretty good start example:
shared_ptr example (it's actually about a vector of smart pointers) or
shared_ptr doc
The following answer by Johannes Schaub explains the boost smart pointers pretty well:
smart pointers explained
The idea behind(in as few words as possible) ptr_vector is that it handles the deallocation of memory behind the stored pointers for you: let's say you have a vector of pointers as in your example. When quitting the application or leaving the scope in which the vector is defined you'll have to clean up after yourself(you've dynamically allocated ANDgate and ORgate) but just clearing the vector won't do it because the vector is storing the pointers and not the actual objects(it won't destroy but what it contains).
// if you just do
G.clear() // will clear the vector but you'll be left with 2 memory leaks
...
// to properly clean the vector and the objects behind it
for (std::vector<gate*>::iterator it = G.begin(); it != G.end(); it++)
{
delete (*it);
}
boost::ptr_vector<> will handle the above for you - meaning it will deallocate the memory behind the pointers it stores.
Through Boost you can do it
>
std::vector<boost::any> vecobj;
boost::shared_ptr<string> sharedString1(new string("abcdxyz!"));
boost::shared_ptr<int> sharedint1(new int(10));
vecobj.push_back(sharedString1);
vecobj.push_back(sharedint1);
>
for inserting different object type in your vector container. while for accessing you have to use any_cast, which works like dynamic_cast, hopes it will work for your need.
#include <memory>
#include <iostream>
class SharedMemory {
public:
SharedMemory(int* x):_capture(x){}
int* get() { return (_capture.get()); }
protected:
std::shared_ptr<int> _capture;
};
int main(int , char**){
SharedMemory *_obj1= new SharedMemory(new int(10));
SharedMemory *_obj2 = new SharedMemory(*_obj1);
std::cout << " _obj1: " << *_obj1->get() << " _obj2: " << *_obj2->get()
<< std::endl;
delete _obj2;
std::cout << " _obj1: " << *_obj1->get() << std::endl;
delete _obj1;
std::cout << " done " << std::endl;
}
This is an example of shared_ptr in action. _obj2 was deleted but pointer is still valid.
output is,
./test
_obj1: 10 _obj2: 10
_obj2: 10
done
The best way to add different objects into same container is to use make_shared, vector, and range based loop and you will have a nice, clean and "readable" code!
typedef std::shared_ptr<gate> Ptr
vector<Ptr> myConatiner;
auto andGate = std::make_shared<ANDgate>();
myConatiner.push_back(andGate );
auto orGate= std::make_shared<ORgate>();
myConatiner.push_back(orGate);
for (auto& element : myConatiner)
element->run();