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

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"

Related

destructor for hashtable separate chaining implementation c++

Hello dear stackoverflow once again I'm here for help!
The idea: I'm implementing HashTable separate chaining based on sets
The problem: The destructor of set do not really work and I have no idea why
The code of set:
class set {
std::list<std::string>* bucket_array;
size_t bucket_array_size;
size_t set_size;
const double max_load_factor = 3.0;
public:
// Creates an empty set
set() :
bucket_array(new std::list<std::string>[4]),
bucket_array_size(4),
set_size(0)
{
}
};
the main problem is HERE:
set::~set(){
for (size_t i=0;i<=bucket_array->size();i++){
for(auto p = bucket_array[i].begin(); p != bucket_array[i].end(); ++p){
bucket_array[i].erase(p);
}
}
delete[] bucket_array;
}
From list::erase:
References and iterators to the erased elements are invalidated.
So when you write
for(auto p = bucket_array[i].begin(); p != bucket_array[i].end(); ++p){
bucket_array[i].erase(p);
you invalidate p and ++p is UB. You have to use the return value of erase:
for(auto p = bucket_array[i].begin();
p != bucket_array[i].end();
p = bucket_array[i].erase(p)) { }
or even simpler:
bucket_array[i].erase(bucket_array[i].begin(),
bucket_array[i].end());
But why do you erase all the lists manually? delete[] bucket_array; will do it automatically.
Even better would be to use std::vector and then even the delete becomes automatic and you wouldn't need set::~set() at all.

Deleting pointers in an unorderd map

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

What is the most concise way to clear a map and delete contents?

I have a std::list and a std::map that I would like to empty and call delete on all the pointers.
After reading this question I am using this for the std::list:
mylist.remove_if([](myThingy* thingy) -> bool { delete thingy; return true; });
Is there something similarly concise for std::map?
Note that I cannot use a range based for loop because it isn't supported by my compiler (VC10). If it would be possible I assume
for(auto* thingy : myMap) { delete thingy; }
myMap.clear();
would work. Please correct me if I am wrong.
Is there something similarly concise for std::map?
You could do it this way (supposing your thingy is the mapped value, and not the key):
for_each(myMap.begin(), myMap.end(),
[] (decltype(myMap)::value_type const& p) { delete p.second; });
myMap.clear();
Concerning the range-based for loop:
If it would be possible I assume
for(auto* thingy : myMap) { delete thingy; }
myMap.clear();
would work. Please correct me if I am wrong.
More or less. You still need to keep in mind that values of a map are actually pairs - but you could fix the range-based for to keep that into account, yes:
for (auto&& p : myMap) { delete p.second; }
myMap.clear();
Anyway, please consider using smart pointers instead of performing manual memory management through raw pointers, new, and delete. This way you would avoid this kind of problems.
I don't think your remove_if solution is a good idea for the
other types, either. Just use a simple loop (or foreach):
for ( auto current = myMap.begin(); current != myMap.end(); ++ current ) {
delete current->second;
}
myMap.clear();
Note that you cannot do a delete current->first; this will
invalidate keys in the map. And unless you are doing
a clear() immediately afterwards (or are destructing the map),
set the deleted pointer to NULL.
With regards to your second question:
for ( auto* thingy : myMap )
would certainly not work. The value type of map is a pair, not
a pointer, so you'ld need somthing like:
for ( auto thingy : myMap ) { delete thingy.second; }
(I think. I've not been able to experiment with this either.)

Deleting entries in STL vector

I want to clean up the threads which pointers are stored in STL vector. I am doing it as below. Is this right way of doing as i am deleting entries while looping thourgh vector or there is better way to do this.
Please suggest.
template <typename threadFuncParamT >
bool ThreadPool<threadFuncParamT>::KillSleepingThreads()
{
if(m_vecThreads.size() != 0)
{
for (; std::vector< ThreadWrapper < threadFuncParamT>* >::iterator itrCollThreads != values.end(); )
{
ThreadWrapper < threadFuncParamT> *pWrapper = m_vecThreads.back();
m_vecThreads.pop_back();
delete pWrapper;
} // for loop
} // if condition
}
Thanks!
If you're allowed to use C++11, then make it cute:
for (auto it = m_vecThreads.begin() ; it != m_vecThreads.end(); ++it )
{
delete *it;
}
m_vecThreads.clear();
You can make it even more cute (in C++11, of course - thanks to #celtschk's comment):
for (auto & ptr: m_vecThreads) //it is called range-based for loop
{
delete ptr;
}
m_vecThreads.clear();
Or if you're not allowed to use C++11, then replace auto (in the first for loop) with this:
typename std::vector<ThreadWrapper<threadFuncParamT*>::iterator
//^^^^^^^^ you've to typename as well
Note that you've to use typename as well, for iterator is a dependent name.
Also, the following is not needed, remove it from your code:
if(m_vecThreads.size() != 0) // not needed!
Try this in your function:
for(size_t i = 0; i < m_vecThreads.size(); ++i)
{
delete m_vecThreads[i];
}
m_vecThreads.clear();
It looks a lot more complicated then it needs to. If you are really trying to just delete every item in the vector, just delete each item then clear the entire vector.
for(std::vector<ThreadWrapper<threadFuncParamT*>>::iterator
i = m_vecThreads.begin();
i != m_vecThreads.end();
++i)
{
delete *i;
}
m_vecThreads.clear();
As an aside, it's usually a better practice to have a vector of smart pointers (eg boost::shared_ptr) than having to explicitly delete items.

Cleaning up an STL list/vector of pointers

What is the shortest chunk of C++ you can come up with to safely clean up a std::vector or std::list of pointers? (assuming you have to call delete on the pointers?)
list<Foo*> foo_list;
I'd rather not use Boost or wrap my pointers with smart pointers.
For std::list<T*> use:
while(!foo.empty()) delete foo.front(), foo.pop_front();
For std::vector<T*> use:
while(!bar.empty()) delete bar.back(), bar.pop_back();
Not sure why i took front instead of back for std::list above. I guess it's the feeling that it's faster. But actually both are constant time :). Anyway wrap it into a function and have fun:
template<typename Container>
void delete_them(Container& c) { while(!c.empty()) delete c.back(), c.pop_back(); }
Since we are throwing down the gauntlet here... "Shortest chunk of C++"
static bool deleteAll( Foo * theElement ) { delete theElement; return true; }
foo_list . remove_if ( deleteAll );
I think we can trust the folks who came up with STL to have efficient algorithms. Why reinvent the wheel?
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
delete *it;
}
foo_list.clear();
If you allow C++11, you can do a very short version of Douglas Leeder's answer:
for(auto &it:foo_list) delete it; foo_list.clear();
It's really dangerous to rely on code outside of the container to delete your pointers. What happens when the container is destroyed due to a thrown exception, for example?
I know you said you don't like boost, but please consider the boost pointer containers.
template< typename T >
struct delete_ptr : public std::unary_function<T,bool>
{
bool operator()(T*pT) const { delete pT; return true; }
};
std::for_each(foo_list.begin(), foo_list.end(), delete_ptr<Foo>());
I'm not sure that the functor approach wins for brevity here.
for( list<Foo*>::iterator i = foo_list.begin(); i != foo_list.end(); ++i )
delete *i;
I'd usually advise against this, though. Wrapping the pointers in smart pointers or using a specialist pointer container is, in general, going to be more robust. There are lots of ways that items can be removed from a list ( various flavours of erase, clear, destruction of the list, assignment via an iterator into the list, etc. ). Can you guarantee to catch them all?
The following hack deletes the pointers when your list goes out of scope using RAII or if you call list::clear().
template <typename T>
class Deleter {
public:
Deleter(T* pointer) : pointer_(pointer) { }
Deleter(const Deleter& deleter) {
Deleter* d = const_cast<Deleter*>(&deleter);
pointer_ = d->pointer_;
d->pointer_ = 0;
}
~Deleter() { delete pointer_; }
T* pointer_;
};
Example:
std::list<Deleter<Foo> > foo_list;
foo_list.push_back(new Foo());
foo_list.clear();
At least for a list, iterating and deleting, then calling clear at the end is a bit inneficient since it involves traversing the list twice, when you really only have to do it once. Here is a little better way:
for (list<Foo*>::iterator i = foo_list.begin(), e = foo_list.end(); i != e; )
{
list<Foo*>::iterator tmp(i++);
delete *tmp;
foo_list.erase(tmp);
}
That said, your compiler may be smart enough to loop combine the two anyways, depending on how list::clear is implemented.
Actually, I believe the STD library provides a direct method of managing memory in the form of the allocator class
You can extend the basic allocator's deallocate() method to automatically delete the members of any container.
I /think/ this is the type of thing it's intended for.
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); it++)
{
delete *it;
}
foo_list.clear();
There's a small reason why you would not want to do this - you're effectively iterating over the list twice.
std::list<>::clear is linear in complexity; it removes and destroys one element at a time within a loop.
Taking the above into consideration the simplest to read solution in my opinion is:
while(!foo_list.empty())
{
delete foo_list.front();
foo_list.pop_front();
}
Since C++11:
std::vector<Type*> v;
...
std::for_each(v.begin(), v.end(), std::default_delete<Type>());
Or, if you are writing templated code and want to avoid specifying a concrete type:
std::for_each(v.begin(), v.end(),
std::default_delete<std::remove_pointer<decltype(v)::value_type>::type>());
Which (since C++14) can be shortened as:
std::for_each(v.begin(), v.end(),
std::default_delete<std::remove_pointer_t<decltype(v)::value_type>>());
void remove(Foo* foo) { delete foo; }
....
for_each( foo_list.begin(), foo_list.end(), remove );
for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
delete *i;
foo_list.clear();
This seems cleanest imo, but your c++ version must support this type of iteration (I believe anything including or ahead of c++0x will work):
for (Object *i : container) delete i;
container.clear();