Using the end iterator will result in undefined behavior.
However, the list can be built in such a way that the list itself is a node, and thus the list is looped. Abstract example:
#include <iostream> #include <string> struct list_node_base //Базовый узел, который содержит два указателя на соседние узлы { list_node_base * next; list_node_base * prev; }; template<typename T> struct list_node: list_node_base //Узел целевого типа добавляет данные к базовому узлу { list_node(T const & src): data(src) { } T data; }; template<typename T> struct list: list_node_base //Список является узлом самого себя, но без данных { struct iterator { T & operator*() { return get_pointer()->data; } T * operator->() { return &get_pointer()->data; } bool operator!=(iterator const & rhv) { return p != rhv.p; } list_node<T> * get_pointer() { return static_cast<list_node<T>*>(p); } iterator & operator++() { p = p->next; return *this; } list_node_base * p; }; list(): list_node_base{this, this} {//Список в начальном состоянии состоит из одного узла - самого списка } void push(T const & v) { list_node_base * p = new list_node<T>{T(v)}; prev->next = p;//this->next исправится автоматически при вставке первого элемента p->prev = prev; p->next = this;//Элемент следующий за последним - сам список prev = p; } iterator begin() { return iterator{next};//На первый узел указывает next } iterator end() { return iterator{this};//Сам список и является узлом end } }; int main() { list<std::string> lst; lst.push("some"); lst.push("unknown"); lst.push("word"); auto current = lst.begin(); for(unsigned i = 0; i < 10; ++i) { if (current != lst.end()) {//Чтобы не разыменовать end std::cout << *current << std::endl;//ведь в нем нет члена data } ++current;//Для нашей реализации это валидно даже для end } }
https://rextester.com/JBC22118
In this list, all nodes except one contain the data member. This "special" node contains the necessary pointers to the first and last elements of the list, and is the basis of the end iterator. Since there is no data member in this node, get_pointer()->data in the iterator will result in undefined behavior.
Such lists are quite simple and easy to implement. The list in gcc is implemented in a similar way:
//g++ 5.4.0 #include <iostream> #include <string> #include <list> int main() { std::list<std::string> lst; lst.push_back("some"); lst.push_back("unknown"); lst.push_back("word"); auto current = lst.begin(); for(unsigned i = 0; i < 10; ++i) { if (current != lst.end()) { std::cout << *current << std::endl; } ++current; } }
https://rextester.com/VMNO65384