2013-03-01 2 views
5

У меня есть список std::list<T *> *l;. этот список не является нулевым и имеет некоторые значения. Моя проблема в том, как правильно обращаться к элементам? Мне не нужно перебирать список. я просто хочу только первый элемент.Как получить доступ к первому элементу std :: list?

std::list<T*>::iterator it = l->begin(); 

if (it != l->end()) 
{ 
    // accessing T 
    int value = (*it)->value(); // Is this safe? 
} 

или я должен также проверить нуль?

if (it != l->end() && (*it)) 
{ 
    // accessing T 
    int value = (*it)->value(); 
} 
+0

Вы держите указатели, так что проверить на 'NULL'. Или используйте 'std :: list '. – juanchopanza

+3

Почему вы решили использовать 'std :: list ' вместо 'std :: list '? – LihO

+0

Действительно ли необходимо использовать необработанные указатели? ... –

ответ

8

Если вы вынуждены использовать std::list<T*> myList; и скажем, что T определяется как:

struct T 
{ 
    T(const char* cstr) : str(cstr){ } 
    std::string str; 
}; 

затем просто использовать std::list::front для доступа к первому элементу:

std::string firstStr = myList.front()->str; 

Обратите внимание, что в этом случае myList.front() возвращается ссылка на первый элемент в вашем списке, который ссылается на указатель в этом случае. Таким образом, вы можете рассматривать его так же, как указатель на первый элемент.

И на ваш вопрос о NULL: Когда вы работаете с контейнером указателей, указатель следует удалить из контейнера после уничтожения объекта. Как только вы начинаете использовать указатели, это обычно означает, что вы являетесь ответственным за управление памятью, связанную с объектами, на которые указывают эти указатели (что является основной причиной, по которой вы должны предпочесть std::list<T> по std::list<T*> всегда, когда это возможно).

Даже хуже, чем NULL указатели повисшие указатели: При создании объекта, хранить его адрес в контейнере, но вы не будете удалять этот адрес из контейнера после того, как объект подорванный, то этот указатель будет становится недействительным и пытается получить доступ к памяти, на которую указывает этот указатель, приведет к неопределенному поведению . Поэтому не только вы должны убедиться, что ваш std::list не содержит указателей NULL, вы также должны убедиться, что он содержит только указатели на действительные объекты, которые все еще существуют.

Так что к тому времени вы будете очистки этих элементов, вы найдете себе удаление указателей из списка и удаления объектов они указывают сразу:

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 
} 

Также стоит прочитать эти вопросы:
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?

+0

is not .front() удаленная функция в настоящее время? если да, то что использовать вместо этого? – serup

0

Необходимость нулевой проверки элемента списка полностью зависит от того, что может быть помещено в список в первую очередь.

Если возможно, что список содержит нулевые указатели, то вам наиболее определенно нужно проверить для NULL перед доступом к элементу.
Если это невозможно, то также нет причин для проверки.

+0

Я не согласен, вы всегда должны проверять NULL, особенно в DEBUG/build. Если это не должно быть NULL, выбросьте исключение. –

+0

@AlexChamberlain: В этом случае почему бы и не проверить, что указатель все еще ссылается на действительный живой объект? –

+0

Если бы я мог придумать какой-то способ, я бы в сборке DEBUG. –

Смежные вопросы