Deleting pointers in an unorderd map - c++

I am in AI trying to clean memory in an unoredered map i used for an A* search and the code below is what i am doing for one of my maps. I can't get it working, I need some help.
for (std::unordered_map<Tile*, PlannerNode*>::iterator itr = plan_map.begin(); itr != plan_map.end(); ++itr)
{
delete itr;
itr->second = nullptr;
}

Since you have an unordered_map of pointers you need to free the space which they point to, i.e. call delete on them. Afterwards you want to erase them from the map rather than setting them to nullptr. The example below might help you. It will print
Destroying Tile
Destroying PlannerNode
on your screen.
#include <iostream>
#include <unordered_map>
struct Tile {
~Tile() { std::cout << "Destroying Tile\n"; }
};
struct PlannerNode {
~PlannerNode() { std::cout << "Destroying PlannerNode\n"; }
};
int main()
{
std::unordered_map<Tile*, PlannerNode*> plan_map;
plan_map.emplace(new Tile, new PlannerNode);
for (auto itr = plan_map.begin(); itr != plan_map.end(); /* no increment here! */)
{
delete itr->first;
delete itr->second;
itr = plan_map.erase(itr);
}
}
It would probably be better to use RAII constructs to manage the pointers, e.g. std::unique_ptr. That way you can just let plan_map go out of scope and all memory is cleaned up automatically for you.
std::unordered_map<std::unique_ptr<Tile>, std::unique_ptr<PlannerNode>> plan_map;
plan_map.emplace(std::make_unique<Tile>(), std::make_unique<PlannerNode>());

std::for_each(plan_map.begin(), plan_map.end(), [](auto& p){delete p.first; delete p.second;});
plan_map.clear();
This is a much cleaner way to do it and it also avoids clumsy iterator aritematic.
Understanding lambda syntax is not in scope of the question, I do recommend looking up C++ lambda's to understand this.
do look into std::unique_ptr<>, that will help you and all you would need to do would be,
plan_map.clear();
reference:http://en.cppreference.com/w/cpp/algorithm/for_each

Related

Use C++17 features to better delete all pointers from a container

Before C++17, deleting all pointers from a map looked like:
for (TMapBuffOnAttrs::iterator it = m_map_buff_on_attrs.begin(); it != m_map_buff_on_attrs.end(); it++)
{
if (NULL != it->second)
{
delete(it->second);
}
}
m_map_buff_on_attrs.clear();
With C++17, we got:
for (auto it = m_map_buff_on_attrs.begin(); it != m_map_buff_on_attrs.end(); it++)
{
if (NULL != it->second)
{
delete(it->second);
}
}
Is there a simpler solution?
Yes.
for (auto it = m_map_buff_on_attrs.begin(); it != m_map_buff_on_attrs.end(); it++)
Since you only use the value *it and no other data from that iterator, a for-range loop would be simpler.
if (NULL != it->second)
{
delete(it->second);
}
Deleting NULL is well-defined and has no effect, this is a test you can skip.
Which gives:
for (auto& p : m_map_buff_on_attrs) {
delete p.second;
}
Manipulating raw pointers is error-prone and makes you write more useless code. If m_map_buff_on_attrs were a map of smart pointers, your code would simply be:
} // m_map_buff_on_attrs goes out of scope and destroys and frees everything.
RAII pattern is your friend:
using TMapBuffOnAttrs = std::map<std::string, std::unique_ptr<Attr>>;
m_map_buff_on_attrs["attrName"] = std::make_unique<Attr>(x, a);
....
// loop is not needed, to delete just do:
m_map_buff_on_attrs.clear();
You can use for_each with lambda function.
Here is a way:
std::for_each(m_map_buff_on_attrs.begin(), m_map_buff_on_attrs.end(),
[](auto &item) {delete item.second;});
Yes, use smartpointers. And simply 'clear()' the container...
Otherwise this is just "C code written in C++17"

Pointer to list element after removal

I have a list that stores objects.
list<MyObject> l;
I also have a method that returns a pointer to one of those objects, if it exists, or nullptr otherwise.
MyObject* get(int x) {
for (std::list<MyObject>::iterator it = l.begin(); it != l.end(); ++it) {
if (it->X == x) {
return &(*it);
}
}
return nullptr;
}
If I get() a pointer to an element, and while I am using it, it gets erased from another thread, the pointer becomes invalid, and weird things happen :)
What I wanted to know is if there is a way of returning some special kind of pointer in get(), so that if I call erase on an element and that element is still being referenced, its memory won't be released until the pointer to it goes out of scope.
I considered using a reference, but I need the possibility of returning nullptr on get, so I can check from the caller if the return was indeed a valid object.
Can someone suggest a better way of doing this, to avoid these memory issues?
As recommended you should use some smart_pointer to manage the shared ownership.
Some recomendations:
Use always as default, std::vector
If could use C++11 use the standard shared_ptr for shared ownership, if not, use boost version.
Use the algorithm header as much as you can (in this case find_if is the right one).
You should also try to use the algorithm for the search of the specific element. Here is some sample code:
#include <algorithm>
#include <iostream>
#include <vector>
#include <memory>
struct MyObject {
int X;
MyObject(int x_value) : X(x_value) {}
};
using element_t = std::shared_ptr<MyObject>;
std::vector<element_t> l{
std::make_shared<MyObject>(3), std::make_shared<MyObject>(4),
std::make_shared<MyObject>(5), std::make_shared<MyObject>(6),
std::make_shared<MyObject>(7), std::make_shared<MyObject>(8)};
element_t get(int x) {
auto it = std::find_if(std::begin(l), std::end(l),
[x](const element_t& elem) { return elem->X == x; });
element_t found;
if (it != std::end(l)) {
found = *it;
}
return found;
}
int main() {
auto f1 = get(6);
if (f1) {
std::cout << "encontrado " << f1->X << std::endl;
} else {
std::cout << "6 no se encontro" << std::endl;
}
auto f2 = get(10);
if (f2) {
std::cout << "encontrado " << f2->X << std::endl;
} else {
std::cout << "10 no se encontro" << std::endl;
}
return 0;
}
Before using smart pointers, you might want to make sure you can spell out the reason why you can't (or don't want to) design a system where your objects have only one owner at a given time.
Smart pointers will avoid invalid data access, but they have all sorts of more or less hidden problems
they cost additional memory, force you to use them and their move semantics everywhere, and might easily become tricky, e.g. if you keep circular references or want an object to return a smart pointer to itself,
std:: containers become basically as useless as when you fill them with any kind of pointers (a vector of pointers is not a vector of objects),
you don't control where the deallocation takes place, so you might have your objects deleted by any task referencing them, possibly a time-critical one,
having no clear idea of who owns what is more often than not a recipe for disaster.
For instance, having one thread decide to delete objects while another grabs some from the same storage without any synchronization is very dangerous indeed. It is a bit as if one thread considered the object invalid while the other would consider it valid.
Does not strike me as the most robust design, but surely you have your reasons.
I think you could start by using unique_ptrs and see if that suits your needs, instead of jumping to shared_ptrs right away.

How to delete raw pointers from a unique_ptr

I'm writing a game framework, I have a vector<unique_ptr<Object>> list and I distribute pointers from that list by calling object.get() and sending that out. Before that I send out references instead of raw pointers but that resulted in other weird problem so I was told this is better. However when I remove a unique_ptr<Object>from the list, the raw pointers remains. I also can't deallocate them manually, I get an exception saying the pointer is not allocated.
So my question would be:
How do I delete raw pointers from removed unique_ptr's?
and is also a more general question:
Am I on the right track structure wise of passing pointers instead of references?
PxlObject* PxlFramework::AddObject(PxlObject* obj)
{
std::unique_ptr<PxlObject> u_ptr(obj);
objects_iterator = objects.insert(objects.end(), std::move(u_ptr));
return obj;
}
void PxlFramework::DeleteObject(PxlObject* obj) {
for(objects_iterator = objects.begin(); objects_iterator != objects.end(); ++objects_iterator)
{
if((*objects_iterator)->get_id() == obj->get_id())
{
//attempting to delete the raw pointer here but it will result in an error
delete obj;
//removing the unique_ptr<PxlObject> from the list here
std::swap((*objects_iterator), objects.back());
objects.pop_back();
break;
}
}
}
The whole point of std::unique_ptr is that it "owns" the object and it manages deletion automatically when the unique_ptr is destroyed. As such, you should not delete either a unique_ptr nor anything that a unique_ptr owns. To avoid this confusion, references are more common. Additionally, you have the oddity that your AddObject returns a pointer to a PxlObject that is not the one just added.
Something like this might be a little cleaner:
template<class Us...>
PxlObject& PxlFramework::AddObject(Us&&... obj)
{
std::unique_ptr<PxlObject> u_ptr(new PxlObject(std::forward<Us>(obj)...));
objects_iterator = objects.insert(objects.end(), std::move(u_ptr));
return **objects_iterator;
}
void PxlFramework::DeleteObject(PxlObject& obj) {
auto finder = [](std::unique_ptr<PxlObject>& p)->bool
{return obj.get_id()==p->get_id();};
auto it = find_if(objects.begin(), objects,end(), finder);
if (it != objects.end())
objects.erase(it);
else
throw ...;
}
You don't need delete the raw pointer directly you can use vector.erase instead. Here you have a simple example:
#include <iostream>
#include <algorithm>
#include <memory>
#include <vector>
using namespace std;
typedef vector<unique_ptr<int>> ptr_list_t;
void remove_number(int x, ptr_list_t& ptr_list)
{
for (ptr_list_t::iterator it = ptr_list.begin(); it != ptr_list.end(); ++it)
if (*(it->get()) == x) {
ptr_list.erase(it); // Use vector.erase for deleting objects from a vector.
// since it points to a unique_ptr, the object owned by it
// will be destroyed automatically.
break;
}
}
int main()
{
ptr_list_t ptr_list;
// Generating the pointer to numbers. 0 - 9
for (int i = 0; i < 10; i++)
ptr_list.push_back(unique_ptr<int>(new int(i)));
// Remove the number 3.
remove_number(3, ptr_list);
// Printing the list. The number 3 will not appear.
for (ptr_list_t::iterator it = ptr_list.begin(); it != ptr_list.end(); ++it)
cout << *(it->get()) << endl;
return 0;
}
Other thing, I'm agreed with #MooingDuck: you should not delete either a unique_ptr nor anything that a unique_ptr owns. But you sure can. Take a look on unique_ptr.release. This function frees the ownership of the managed object.

why does returning a map.insert().second introduce unreachable memory?

The following code:
~A()
{
for (itr = mymap.begin(); itr != mymap.end() ++itr)
{
delete itr->second //the map look like this <std::string , T*>
}
}
A::Addnew(std::string name)
{
return mymap.insert(std::pair<std::string,T*>(name, new T)).second;
}
introduces a memory leak, but if I change the AddNew() member function to:
itr = mymap.find(name);
if(itr == mymap.end())
{
return mymap.insert(std::pair<std::string,T*>(name, new T)).second;
}
then there is no memory leak.
It seems like if I called the first case accidentally, I will introduce lots of new T, but my mymap.size() cannot keep track of it. Can anyone explain this?
std::map::insert() is a no-op if the key already exists in the map.
If you try to insert a duplicate key, the first version of your code will leak the object it has allocated using new.
The second version does not have this problem since you don't call new unless you've established that the key doesn't exist in the map.
Two good ways to fix the leak are:
store the objects by value;
store smart pointers to objects.
In your first AddNew function:
when you are inserting a member whose key have existed in the map,
you will create a T object,but you do not release it:
you can do like this:
A::Addnew(std::string name)
{
T *temp = new T;
if(mymap.insert(std::pair<std::string,T*>(name, temp)).second)
return true;
else
{
delete temp;
return false;
}
}

C++: Why is the destructor being called here?

I guess I don't fully understand how destructors work in C++. Here is the sample program I wrote to recreate the issue:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
struct Odp
{
int id;
Odp(int id)
{
this->id = id;
}
~Odp()
{
cout << "Destructing Odp " << id << endl;
}
};
typedef vector<shared_ptr<Odp>> OdpVec;
bool findOdpWithID(int id, shared_ptr<Odp> shpoutOdp, OdpVec& vec)
{
shpoutOdp.reset();
for (OdpVec::iterator iter = vec.begin(); iter < vec.end(); iter++)
{
Odp& odp = *(iter->get());
if (odp.id == id)
{
shpoutOdp.reset(iter->get());
return true;
}
}
return false;
}
int main()
{
OdpVec vec;
vec.push_back(shared_ptr<Odp>(new Odp(0)));
vec.push_back(shared_ptr<Odp>(new Odp(1)));
vec.push_back(shared_ptr<Odp>(new Odp(2)));
shared_ptr<Odp> shOdp;
bool found = findOdpWithID(0, shOdp, vec);
found = findOdpWithID(1, shOdp, vec);
}
Just before main() concludes, the output of this program is:
Destructing Odp 0
Destructing Odp 1
Why does this happen? I'm retaining a reference to each of the Odp instances within the vector. Does it have something to do with passing a shared_ptr by reference?
UPDATE I thought that shared_ptr::reset decremented the ref count, based on MSDN:
The operators all decrement the
reference count for the resource
currently owned by *this
but perhaps I'm misunderstanding it?
UPDATE 2: Looks like this version of findOdpWithID() doesn't cause the destructor to be called:
bool findOdpWithID(int id, shared_ptr<Odp> shpoutOdp, OdpVec& vec)
{
for (OdpVec::iterator iter = vec.begin(); iter < vec.end(); iter++)
{
Odp& odp = *(iter->get());
if (odp.id == id)
{
shpoutOdp = *iter;
return true;
}
}
return false;
}
This line right here is probably what is tripping you up.
shpoutOdp.reset(iter->get());
What you're doing here is getting (through get()) the naked pointer from the smart pointer, which won't have any reference tracking information on it, then telling shpoutOdp to reset itself to point at the naked pointer. When shpoutOdp gets destructed, it's not aware that there is another shared_ptr that points to the same thing, and shpoutOdp proceeds to destroy the thing it's pointed to.
You should just do
shpoutOdp = *iter;
which will maintain the reference count properly. As an aside, reset() does decrement the reference counter (and only destroys if the count hits 0).
So many things that are being used nearly correctly:
bool findOdpWithID(int id, shared_ptr<Odp> shpoutOdp, OdpVec& vec)
Here the parameter shpoutOdp is a a copy of the input parameter. Not such a big deal considering it is a shared pointer but that is probably not what you were intending. You probably wanted to pass by reference otherwise why pass it to the function in the first place.
shpoutOdp.reset();
Resetting a parameter as it is passed in.
Does this mean it could be dirty (then why have it as an input parameter) it make the function return a shared pointer as a result if you want to pass something out.
Odp& odp = *(iter->get());
Don't use get on shared pointers unless you really need to (and you really if ever need too). Extracting the pointer is not necessary to get at what the pointer points at and makes you more likely to make mistakes because you are handling pointers. The equivalent safe(r) line is:
Odp& odp = *(*iter); // The first * gets a reference to the shared pointer.
// The second star gets a reference to what the shared
//pointer is pointing at
This is where it all goes wrong:
shpoutOdp.reset(iter->get());
You are creating a new shared pointer from a pointer. Unfortunately the pointer is already being managed by another shared pointer. So now you have two shared pointers that think they own the pointer and are going to delete it when they go out of scope (the first one goes out of scope at the end of the function as it is a copy of the input parameter (rather than a reference)). The correct thing to do is just to do an assignment. Then the shared pointers know they are sharing a pointer:
shpoutOdp = *iter; // * converts the iterator into a shared pointer reference
The next line though not totally wrong does assume that the iterators used are random access (which is true for vector).
for (OdpVec::iterator iter = vec.begin(); iter < vec.end(); iter++)
But this makes the code more brittle as a simple change in the typedef OdpVec will break the code without any warning. So to make this more consistent with normal iterator usage, use != when checking against end() and also prefer the pre increment operator:
for (OdpVec::iterator iter = vec.begin(); iter != vec.end(); ++iter)
shared_ptr::reset destroys the contents already in the shared_ptr. If you want to affect only that single shared_ptr reference, simply assign to it.
EDIT: In response to comment, you can fix it by changing the body of your for loop to:
if ((*iter)->id == id)
{
shpoutOdp = *iter;
return true;
}
EDIT2: That all said, why aren't you using std::find_if here?
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm> //for std::find_if
#include <functional> //for std::bind
struct Odp
{
int id;
int GetId()
{
return id;
}
Odp(int id)
{
this->id = id;
}
~Odp()
{
std::cout << "Destructing Odp " << id << std::endl;
}
};
typedef std::vector<shared_ptr<Odp> > OdpVec;
int main()
{
OdpVec vec;
vec.push_back(std::shared_ptr<Odp>(new Odp(0)));
vec.push_back(std::shared_ptr<Odp>(new Odp(1)));
vec.push_back(std::shared_ptr<Odp>(new Odp(2)));
OdpVec::iterator foundOdp = std::find_if(vec.begin(), vec.end(),
std::bind(std::equal_to<int>(), 0, std::bind(&Odp::GetId,_1)));
bool found = foundOdp != vec.end();
}
The nice thing about shared_ptr is that it handles the ref-counting internally. You don't need to manually increment or decrement it ever. (And that is why shared_ptr doesn't allow you to do so either)
When you call reset, it simply sets the current shared_ptr to point to another object (or null). That means that there is now one less reference to the object it pointed to before the reset, so in that sense, the ref counter has been decremented. But it is not a function you should call to decrement the ref counter.
You don't ever need to do that. Just let the shared_ptr go out of scope, and it takes care of decrementing the reference count.
It's an example of RAII in action.
The resource you need to manage (in this case the object pointed to by the shared_ptr) is bound to a stack-allocated object (the shared_ptr itself), so that its lifetime is managed automatically. The shared_ptr's destructor ensures that the pointed-to object is released when appropriate.