I have a hashmap which contains items of struct Foo (not pointers). Now, I want to have pointers of those items in a list. How can I do this?
I have tried to iterate the hashmap and insert the &*iter's to the list but the pointers get invalidated as soon as they are out of scope.
I should be able to do this without dynamic allocation, shouldn't I?
I do like this and it does not work:
for(...)
{
Foo& bar = *iter;
list.insert(&bar);
}
Pointers to items in the hashmap will become invalid the same time iterators become invalid.
If you leave the hashmap alone (i.e. don't insert/delete/copy/anything after you have iterated it and taken addresses of its elements), your pointers should remain valid.
I have a hashmap which contains items
of struct Foo (not pointers). Now, I
want to have pointers of those items
in a list. How can I do this?
Like this:
typedef Whatever_Hash_Map<Foo> Container;
Container container;
...populate container...
std::list<Foo*> l;
for (Container::const_iterator i = container.begin(); i != container.end(); ++i)
l.insert(&*i);
...use list...
I have tried to iterate the hashmap
and insert the &*iter's to the list
but the pointers get invalidated as
soon as they are out of scope.
You can't use this list if you let anything go out of scope. If you need the list to persist past the return of the function that creates it, be sure to allocate the list itself on the heap and return a pointer to it.
I should be able to do this without
dynamic allocation, shouldn't I?
A list allocates nodes dynamically. The Hash Map probably internally allocates buckets dynamically. But, you don't have to explicitly allocate pointers-to-Foos dynamically - all the Standard and similar containers would copy the Foos onto the heap using value semantics (i.e. Foo's copy constructor or assignment operator).
I do like this and it does not work:
for(...) { Foo& bar = *iter;
list.insert(&bar); }
That in and of itself looks fine, the error is elsewhere in your code. That's why you should follow James' suggestion and post enough code that we can point out your error.
Related
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++.
I have a list std::list<T *> *l;. this list is not null and has some values. My problem is how to access items properly? i do not need to iterate over the list. i just want the first item only.
std::list<T*>::iterator it = l->begin();
if (it != l->end())
{
// accessing T
int value = (*it)->value(); // Is this safe?
}
or should i check for null also?
if (it != l->end() && (*it))
{
// accessing T
int value = (*it)->value();
}
If you are forced to use std::list<T*> myList; and let's say that T is defined as:
struct T
{
T(const char* cstr) : str(cstr){ }
std::string str;
};
then just use std::list::front to access first element:
std::string firstStr = myList.front()->str;
Note that in this case myList.front() returns a reference to first element in your list, which is reference to pointer in this case. So you can treat it just like a pointer to the first element.
And to your question about the NULL: When you work with the container of pointers, the pointer should be removed from the container once the object is destructed. Once you start using pointers, it usually means that you are the one who becomes responsible for the memory management connected with objects that these pointers point to (which is the main reason why you should prefer std::list<T> over std::list<T*> always when possible).
Even worse than NULL pointers are dangling pointers: When you create an object, store its address in your container, but you will not remove this address from your container once the object is destructed, then this pointer will become invalid and trying to access the memory that this pointer points to will produce undefined behavior. So not only that you should make sure that your std::list doesn't contain NULL pointers, you should also make sure it contains only pointers to valid objects that still exist.
So by the time you will be cleaning up these elements, you will find yourself removing pointers from your list and deleting objects they point to at once:
std::list<T*> myList;
myList.push_back(new T("one"));
myList.push_back(new T("two"));
myList.push_back(new T("three"));
myList.push_back(new T("four"));
while (!myList.empty())
{
T* pT = myList.front(); // retrieve the first element
myList.erase(myList.begin()); // remove it from my list
std::cout << pT->str.c_str() << std::endl; // print its member
delete pT; // delete the object it points to
}
It's also worth to read these questions:
Can you remove elements from a std::list while iterating through it?
Doesn't erasing std::list::iterator invalidates the iterator and destroys the object?
The need for a null-check of the list element depends entirely on what can be put into the list in the first place.
If it is possible that the list contains null pointers, then you most definitely should check for for NULL before accessing the element.
If it is not possible, then there is also no reason to check.
This code is written on fly, plz ignore syntax mistakes if any.
std::list<MY_STRUCT> myList;
MY_STRUCT theStruct;
myList.push_back( theStruct );
myList.push_back( theStruct );
// assume I store the pointer of the last item (the 2nd item in this case).
MY_STRUCT * item2 = &myList.back();
// I added another item
myList.push_back( theStruct );
// now I want to delete item2 that I stored bases on its pointer.
// Can myList.remove_if(...) help if so how?
I want to delete the middle item in the list by its pointer (assume I have the pointer value).
I know I can iterate through the list and look for this pointer but is there a better way? Does STL provide a function to do it..Can I use remove_if() in this case to delete the item?
Instead of keeping a pointer to the object you want to remove, why not keep an iterator?
std::list<MY_STRUCT>::iterator item2 = --mylist.end();
The remove_if algorithm doesn't actually remove anything, it just shifts stuff around. It has no knowledge of the container that the iterators point to. Of course the member function remove_if of std::list is a different thing altogether as pointed out in the comments.
Sure, list::remove_if uses whatever condition you give it. For example
template <typename T>
struct AddressIs {
T *ptr;
AddressIs(T *ptr) : ptr(ptr) {}
bool operator()(const T &object) const {
return ptr == &object;
}
};
myList.remove_if(AddressIs<MY_STRUCT>(item2));
Mankarse's point is good though - if you can use an iterator instead of a pointer to identify the item you're interested in, then you don't need to mess about with this.
Beware also that we're relying here on the fact that the address of an item in a list stays the same forever. That isn't always true of all collections, for example vector might have to relocate all the data when you call push_back. If it does, then your middle item is no longer pointed to by item2. Each collection documents which operations can invalidate iterators and/or references to elements.
Instead of getting the back item, you could get the end iterator, make sure it's not begin, decrement by one to point to the last item, and then erase that iterator directly whenever you want.
I think remove_if is a little bit of overkill for what zadane is trying to do. All that needs to be accomplished is to save the location or value of an item in order to delete that specific item later.
As Mark suggested you can store the iterator to the object and use it to delete the item with an erase call, like below:
MY_STRUCT struct;
myList.push_back(struct);
myList.push_back(struct);
std::list<MY_STRUCT>::iterator del_it = myList.end() - 1;
myList.erase(del_it);
Or, if your structure has the == operator defined for MY_STRUCT, you can store the value of the object itself and use the remove method
MY_STRUCT struct1;
MY_STRUCT struct2;
myList.push_back(struct1);
myList.push_back(struct2);
myList.remove(struct2);
Of course if you make your list a list of pointers then you don't have to worry about the == operator as it is already defined for pointer types. Just make sure that if you're iterating through the list and call erase, you need to update your iterator with the returned value.
Also, the remove method removes all elements of the passed value, so if you only want to remove 1 item at a time save the iterator and not the value.
This code is untested so I welcome any corrections.
I generally avoid std::list, but in a case where I'm storing pointers, would it be more advantageous to use a std::list since I could then randomly insert pointers without having to move all my other pointers? What advantages and disadvantages would this present over a std::vector<Some*>
Thanks
Since copy construction of a pointer is trivial, the decision here is not about whether one or the other is better for storing pointers but which is better for your needs.
If you really need to do lots of random inserts (and deletes?) then list could work better though it's not a simple decision - perhaps a vector with reserved space would be preferable, even then. Do you want the per-node overhead of a list just to store a pointer? On 32-bit Windows, that's 12 bytes per entry in the list, plus heap management overhead for a total of 20+ bytes per entry. This does not help data locality over time either. Meanwhile, vector uses four bytes per entry (again on 32-bit) and is guaranteed to store its elements in a contiguous block.
You have to deal with memory cleanup on erase/clear/destruction of the container either way, unless you wrap the pointer element as a smart pointer of some kind. An alternative to ease memory management of your Some*s would be one of the Boost pointer containers.
See also here for some analysis of list, vector and deque. Personally, I'm increasingly of the opinion that list is not that useful in the mainstream.
I think it's especially pointers where using std::vector instead of std::list should be considered even with many insertions/removals at random positions. Pointers are very cheap to copy (in fact, I'd expect my standard library implementation to use CPU intrinsics to do this), so that the higher locality of std::vector's data might by far outweigh the theoretically better fitness of std::list for random insertions/removals.
Anyway, you will have to measure your application (and not an artificial test case) to know for sure.
In general, your first choice should be vector -- also, when you store pointers.
Compare the decision with this question in C (-ish): When do I choose
struct linked_items {
element *item;
linked_items *next;
};
over
element* items[]; /* array of pointers to items */
?
There are cases, but first check if you can apply the "easier" data structure, i.e. the vector.
Generally when you need a container which stores something and then randomly deletes it then the best would be a set. To delete something you need to find it first, which is O(n) for vector and list and O(log(n)) for set. If found then deleting it is instant for list but O(n) for vector, and again O(log(n)) for set.
So:
consider vector if you very rarely
search or delete from this
container;
consider list if you very rarely search in container;
consider set otherwise.
A vector is the most memory and cache efficient. If you know number of elements then using reserve() you can make it 100% memory efficient.
Based on bench marking studies, I prefer to use vector unless there are other strong use cases to support linked list (with some overhead info). But take care of the insertion and removal inefficiencies (on average) in a better way.
Here goes my thoughts:
vector<SomeObject*> vecSomeObjectPointers;
vector<size_t> vecInvalidPointerIndices;// could be zero size, if no objects are removed
Creating/adding new SomeObject element:
void AddNewObject()
{
SomeObject* ptrSomeObject = new SomeObject;
ptrSomeObject->PopulateSomeObject(); // add any extra memory if needed by SomeObject members
ptrSomeObject->DoAnyOtherWorkOnSomeObjectBeforeStoring();
size_t TotalInValidIndices = vecInvalidPointerIndices.size();
if(TotalInValidIndices > 0)
{
//re-use the invalid location/index of vector to hold new object
vecSomeObjectPointers[vecInvalidPointerIndices[TotalInValidIndices-1]] = ptrSomeObject;
vecInvalidPointerIndices.pop_back();
}
else vecSomeObjectPointers.push_back(ptrSomeObject); // new Object pointer at the end
}
Deleting an existing SomeObject element:
void DeleteAnExistingObject()
{
//Find the index of the object to be deleted based on certain input criteria. Ex: value stored etc..
SomeObject* ptrSomeObject;
for(auto& itr=vecSomeObjectPointers.begin(); itr != vecSomeObjectPointers.end(); ++itr)
{
ptrSomeObject = itr;
if(ptrSomeObject->SomeObjectDeletionCriteriaSatisfied())
{
// make sure to delete any extra memory allocated to SomeObject members
delete ptrSomeObject; // re-claim allocated memory
// just invalidate the pointer info rather deleting it from vector to save re-shuffling time
itr = NULL;
//Store the corresponding index to be used for holding a new object to be inserted next time
vecInvalidPointerIndices.push_back(itr - vecSomeObjectPointers.begin());
}
}
}
Working on existing SomeObject elements of the vector using Linear Search time:
void DoSomeWorkOnAnExistingObject()
{
SomeObject* ptrSomeObject;
for(auto& itr=vecSomeObjectPointers.begin(); itr != vecSomeObjectPointers.end(); ++itr)
{
if(itr == NULL) continue;
//Do some work on object data to maintain it
ptrSomeObject = itr;
}
}
Any other thoughts are welcome...
I assume you ask about [std::list<Foo*> would be really slow due to many indirections]
std::vector<Foo*> objects
Vs
std::list<Foo> objects
std::vector:
Fast traversal
Random access to different Foo objects
Foo can be abstract
You need to deleteyour objects manually
Slow insertion if not at the end
std::list:
No need to manually delete objects
Fast insertion
Slow traversal
No random access to different Foo objects
Foo cannot be abstract
EDIT:
I realised that there is one situation when std::vector does not work unless your objects are owned by someone else. Consider this recursive thing
class Foo
{
public:
~Foo(); /**<Now this must be recursive, otherwise it would need std::stack, which results in potential exception from dtor!*/
private:
std::vector<Foo*> m_children;
};
I'm having a std::vector with elements of some class ClassA. Additionally I want to create an index using a std::map<key,ClassA*> which maps some key value to pointers to elements contained in the vector.
Is there any guarantee that these pointers remain valid (and point to the same object) when elements are added at the end of the vector (not inserted). I.e, would the following code be correct:
std::vector<ClassA> storage;
std::map<int, ClassA*> map;
for (int i=0; i<10000; ++i) {
storage.push_back(ClassA());
map.insert(std::make_pair(storage.back().getKey(), &(storage.back()));
}
// map contains only valid pointers to the 'correct' elements of storage
How is the situation, if I use std::list instead of std::vector?
Vectors - No. Because the capacity of vectors never shrinks, it is guaranteed that references, pointers, and iterators remain valid even when elements are deleted or changed, provided they refer to a position before the manipulated elements. However, insertions may invalidate references, pointers, and iterators.
Lists - Yes, inserting and deleting elements does not invalidate pointers, references, and iterators to other elements
As far as I understand, there is no such guarantee. Adding elements to the vector will cause elements re-allocation, thus invalidating all your pointers in the map.
Use std::deque! Pointers to the elements are stable when only push_back() is used.
Note: Iterators to elements may be invalidated! Pointers to elements won't.
Edit: this answer explains the details why: C++ deque's iterator invalidated after push_front()
I'm not sure whether it's guaranteed, but in practice storage.reserve(needed_size) should make sure no reallocations occur.
But why don't you store indexes?
It's easy to convert indexes to iterators by adding them to the begin iterator (storage.begin()+idx) and it's easy to turn any iterator into a pointer by first dereferencing it, and then taking its address (&*(storage.begin()+idx)).
Just make them both store pointers an explicitly delete the objects when you don't need them.
std::vector<ClassA*> storage;
std::map<int, ClassA*> map;
for (int i=0; i<10000; ++i) {
ClassA* a = new ClassA()
storage.push_back(a)
map.insert(std::make_pair(a->getKey(), a))
}
// map contains only valid pointers to the 'correct' elements of storage
From one of the comments to another answer, it seems as if all that you want is centralize (ease) memory management. If that is really the case, you should consider using prepackaged solutions like the boost pointer container library and keep your own code as simple as possible.
In particular, take a look at ptr_map
for vectors no.
for lists yes.
how?
iterator works as a pointer to a particular node in the list.
so you can assign values to any struct like:
list mylist;
pair< list::iterator ,int > temp;
temp = make_pair( mylist.begin() , x );