16

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();
}
STF
  • 1,485
  • 3
  • 19
  • 36
shan
  • 1,164
  • 4
  • 14
  • 30

2 Answers2

19

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?

Community
  • 1
  • 1
LihO
  • 41,190
  • 11
  • 99
  • 167
0

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.

Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41