How to access the first element of std::list? - 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.

Related

Erase element from std::list using a pointer?

class SororityBeerExpo{
public:
std::list<LaysCrankdPepChip> m_chipList;
void destroyChip(LaysCrankdPepChip * target)
{
// m_chipList needs to erase that which is pointed at by target but
// erase() requires an iterator which is not what we got to work with
// remove() needs a value which is not right either
}
}
My question, is how would one delete an element in a list, with a pointer that points to that element? I would like to do this without using Iterators in place of pointers.
You can do a [linear] search for the element in the list, comparing the address of each element to your pointer (std::find_if will fit the bill). Of course, you will still be using an iterator in the end, because that's what list::erase needs.
You can't do it directly (although see Benjamin's answer for an indirect way of doing it). A list node contains more data than just the object being contained (e.g. pointers to the previous and next nodes), but your raw pointer only points to the contained object.

Is it safe to hold pointers to iterators in C++?

I will ask the question first and the motivation next, and finally an illustrative code sample which compiles and executes as expected.
Question
If I can assure myself that an iterator will not get invalidated in the duration when I will be needing to use it, is it safe to hold a pointer to an iterator (e.g. a pointer to a list<int>::iterator).
Motivation
I have multiple containers and I need direct cross references from items held in one container to the corresponding items held in another container and so on. An item in one container might not always have a corresponding item in another container.
My idea thus is to store a pointer to an iterator to an element in container #2 in the element stored in container #1 and so forth. Why? Because once I have an iterator, I can not only access the element in container #2, but if needed, I can also erase the element in container #2 etc.
If there is a corresponding element in container #2, I will store a pointer to the iterator in the element in container #1. Else, this pointer will be set to NULL. Now I can quickly check that if the pointer to the iterator is NULL, there is no corresponding element in container #2, if non-NULL, I can go ahead and access it.
So, is it safe to store pointers to iterators in this fashion?
Code sample
#include <iostream>
#include <list>
using namespace std;
typedef list<int> MyContainer;
typedef MyContainer::iterator MyIterator;
typdef MyIterator * PMyIterator;
void useIter(PMyIterator pIter)
{
if (pIter == NULL)
{
cout << "NULL" << endl;
}
else
{
cout << "Value: " << *(*pIter) << endl;
}
}
int main()
{
MyContainer myList;
myList.push_back(1);
myList.push_back(2);
PMyIterator pIter = NULL;
// Verify for NULL
useIter(pIter);
// Get an iterator
MyIterator it = myList.begin();
// Get a pointer to the iterator
pIter = & it;
// Use the pointer
useIter (pIter);
}
Iterators are generally handled by value. For instance, begin() and end() will return an instance of type iterator (for the given iterator type), not iterator& so they return copies of a value every time.
You can of course take an address to this copy but you cannot expect that a new call to begin() or end() will return an object with the same address, and the address is only valid as long as you hold on to the iterator object yourself.
std::vector<int> x { 1, 2, 3 };
// This is fine:
auto it = x.begin();
auto* pi = &it;
// This is not (dangling pointer):
auto* pi2 = &x.begin();
It rarely makes sense to maintain pointers to iterators: iterators are already lightweight handles to data. A further indirection is usually a sign of poor design. In your example in particular the pointers make no sense. Just pass a normal iterator.
The problem with iterators is that there are a lot of operations on containers which invalidate them (which one depend on the container in question). When you hold an iterator to a container which belongs to another class, you never know when such an operation occurs and there is no easy way to find out that the iterator is now invalid.
Also, deleting elements directly which are in a container which belongs to another class, is a violation of the encapsulation principle. When you want to delete data of another class, you should better call a public method of that class which then deletes the data.
Yes, it is safe, as long as you can ensure the iterators don't get invalidated and don't go out of scope.
Sounds scary. The iterator is an object, if it leaves scope, your pointer is invalid. If you erase an object in container #2, all iterators may become invalid (depending on the container) and thus your pointers become useless.
Why don't you store the iterator itself? For the elements in container #1 that don't refer to anything, store container2.end().
This is fine as long as iterators are not invalidated. If they are, you need to re-generate the mapping.
Yes it is possible to work on pointers to iterators like it is to other types but in your example it is not necessary since you can simple pass the pass the original iterator as reference.
In general it is not a good idea to store iterators since the iterator may become invalid as you modify the container. Better store the containers and create iterators as you need them.

Can I delete a item from std::list based on pointer value?

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.

C++: Copying hashmap contents to pointer list

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.

Returning a pointer to a vector element in c++

I have a vector of myObjects in global scope.
I have a method which uses a std::vector<myObject>::const_iterator to traverse the vector, and doing some comparisons to find a specific element.
Once I have found the required element, I want to be able to return a pointer to it (the vector exists in global scope).
If I return &iterator, am I returning the address of the iterator or the address of what the iterator is pointing to?
Do I need to cast the const_iterator back to a myObject, then return the address of that?
Return the address of the thing pointed to by the iterator:
&(*iterator)
Edit: To clear up some confusion:
vector <int> vec; // a global vector of ints
void f() {
vec.push_back( 1 ); // add to the global vector
vector <int>::iterator it = vec.begin();
* it = 2; // change what was 1 to 2
int * p = &(*it); // get pointer to first element
* p = 3; // change what was 2 to 3
}
No need for vectors of pointers or dynamic allocation.
Returning &iterator will return the address of the iterator. If you want to return a way of referring to the element return the iterator itself.
Beware that you do not need the vector to be a global in order to return the iterator/pointer, but that operations in the vector can invalidate the iterator. Adding elements to the vector, for example, can move the vector elements to a different position if the new size() is greater than the reserved memory. Deletion of an element before the given item from the vector will make the iterator refer to a different element.
In both cases, depending on the STL implementation it can be hard to debug with just random errors happening each so often.
EDIT after comment: 'yes, I didn't want to return the iterator a) because its const, and b) surely it is only a local, temporary iterator? – Krakkos'
Iterators are not more or less local or temporary than any other variable and they are copyable. You can return it and the compiler will make the copy for you as it will with the pointer.
Now with the const-ness. If the caller wants to perform modifications through the returned element (whether pointer or iterator) then you should use a non-const iterator. (Just remove the 'const_' from the definition of the iterator).
You can use the data function of the vector:
Returns a pointer to the first element in the vector.
If don't want the pointer to the first element, but by index, then you can try, for example:
//the index to the element that you want to receive its pointer:
int i = n; //(n is whatever integer you want)
std::vector<myObject> vec;
myObject* ptr_to_first = vec.data();
//or
std::vector<myObject>* vec;
myObject* ptr_to_first = vec->data();
//then
myObject element = ptr_to_first[i]; //element at index i
myObject* ptr_to_element = &element;
It is not a good idea to return iterators. Iterators become invalid when modifications to the vector (inversion\deletion ) happens. Also, the iterator is a local object created on stack and hence returning the address of the same is not at all safe. I'd suggest you to work with myObject rather than vector iterators.
EDIT:
If the object is lightweight then its better you return the object itself. Otheriwise return pointers to myObject stored in the vector.
As long as your vector remains in global scope you can return:
&(*iterator)
I'll caution you that this is pretty dangerous in general. If your vector is ever moved out of global scope and is destructed, any pointers to myObject become invalid. If you're writing these functions as part of a larger project, returning a non-const pointer could lead someone to delete the return value. This will have undefined, and catastrophic, effects on the application.
I'd rewrite this as:
myObject myFunction(const vector<myObject>& objects)
{
// find the object in question and return a copy
return *iterator;
}
If you need to modify the returned myObject, store your values as pointers and allocate them on the heap:
myObject* myFunction(const vector<myObject*>& objects)
{
return *iterator;
}
That way you have control over when they're destructed.
Something like this will break your app:
g_vector<tmpClass> myVector;
tmpClass t;
t.i = 30;
myVector.push_back(t);
// my function returns a pointer to a value in myVector
std::auto_ptr<tmpClass> t2(myFunction());
Say, you have the following:
std::vector<myObject>::const_iterator first = vObj.begin();
Then the first object in the vector is: *first. To get the address, use: &(*first).
However, in keeping with the STL design, I'd suggest return an iterator instead if you plan to pass it around later on to STL algorithms.
You are storing the copies of the myObject in the vector. So I believe the copying the instance of myObject is not a costly operation. Then I think the safest would be return a copy of the myObject from your function.
Refer to dirkgently's and anon's answers, you can call the front function instead of begin function, so you do not have to write the *, but only the &.
Code Example:
vector<myObject> vec; //You have a vector of your objects
myObject first = vec.front(); //returns reference, not iterator, to the first object in the vector so you had only to write the data type in the generic of your vector, i.e. myObject, and not all the iterator stuff and the vector again and :: of course
myObject* pointer_to_first_object = &first; //* between & and first is not there anymore, first is already the first object, not iterator to it.
I'm not sure if returning the address of the thing pointed by the iterator is needed.
All you need is the pointer itself. You will see STL's iterator class itself implementing the use of _Ptr for this purpose. So, just do:
return iterator._Ptr;