Home | Projects | Notes > C++ Programming > Sequence Container - std::list, std::forward_list
std::list, std::forward_list
Sequence containers.
Non-contiguous in memory.
No direct access to elements using [] or at().
Very efficient for inserting and deleting elements once an element is found.
std::list

Declared in the <list> header file.
Dynamic size
Doubly-linked lists of elements.
Supports bi-directional traverse.
Direct element access is NOT provided.
Rapid insertion and deletion of elements anywhere in the container - Constant time: O(1)
If you need a container where you'll have lots of insertions and deletions from the container and you don't need direct access to the elements, then the list is a good choice.
All iterators are available but may become invalid when the corresponding element is deleted.
x
1// Initialization2std::list<int> l1{1, 2, 3, 4, 5};3std::list<int> l2(10, 100); // ten 100s - overloaded constructor4
5// Initialization6std::list<std::string> l3{7 std::string{"Kyungjae"},8 "Sunny", // C-style string will be converted to a std::string.9 std::string{"Yena"}10};11
12// Assignment via initializer list13l1 = {2, 4, 6, 8, 10};For more information, see cppreference.com.
341std::list<int> l1{1, 2, 3, 4, 5};2std::list<int> l2{10, 20, 30, 40, 50};3
4std::cout << l1.size(); // 55std::cout << l1.max_size(); // A very large number6std::cout << l1.front(); // 1 (Returns reference to the first element)7std::cout << l1.back(); // 5 (Returns reference to the last element)8std::cout << l1.empty(); // 0 (false)9
10// The following won't work since std::sort() requires random access11// iterators, and std::list provides only bidirectional iterators.12//std::sort(l1.begin(), l1.end());13
14l1.sort();15
16auto it = std::find(l1.begin(), l1.end(), 3);17l1.insert(it, 10); // 1, 2, 10, 3, 4, 518l1.erase(it); // erase 3. now 1, 2, 10, 4, 5 ('it' becomes invalid) 19
20it = std::find(l1.begin(), l1.end(), 4);21l1.insert(it, l2.begin(), l2.end());22 // 1, 2, 10, 10, 20, 30, 40, 50, 4, 523
24// Lists are bi-directional, so iterators can iterate in both directions.25std::cout << *it; // 426it++;27std::cout << *it; // 528it--;29std::cout << *it; // 430
31l1.resize(2); // 1, 232l1.resize(5); // 1, 2, 0, 0, 033
34l1.swap(l2); // Swaps the two dequesL17: The list will insert an element very efficiently before 3 and the
itwill still reference 3.
The std::list allows for efficiently inserting and deleting elements at the front and back:
91person p{"Kyungjae", 30};2std::list<person> d;3
4l.push_back(p); // Add p to the back (copy is made)5l.pop_back(); // Remove the last element (p in this case)6l.push_front(person{"Sunny", 20});7l.pop_front(); // Remove element from the front8l.emplace_front("Yena", 5); // Construct the object in-place. Very efficient!9l.emplace_back("Sunny", 20); // Construct the object in-place. Very efficient!
std::forward_list (C++11)

Declared in the <forward_list> header file. Introduced in C++11.
Dynamic size
Singly-linked lists of elements.
Supports uni-directional traverse only. (Does not have the concept of "back".)
Less overhead than a std::list.
Direct element access is NOT provided.
Rapid insertion and deletion of elements anywhere in the container - Constant time: O(1)
If you need a container where you'll have lots of insertions and deletions from the container and you don't need direct access to the elements, then the list is a good choice.
Reverse iterators are not available.
Iterators may become invalid when the corresponding element is deleted.
131// Initialization2std::deque<int> d1{1, 2, 3, 4, 5};3std::deque<int> d2(10, 100); // ten 100s4
5// Initialization6std::deque<std::string> d3{7 std::string{"Kyungjae"},8 "Sunny", // C-style string will be converted to a std::string.9 std::string{"Yena"}10};11
12// Assignment via initializer list13d1 = {2, 4, 6, 8, 10};For more information, see cppreference.com.
341std::list<int> l1{1, 2, 3, 4, 5};2std::list<int> l2{10, 20, 30, 40, 50};3
4//std::cout << l1.size(); // size() not supported5std::cout << l1.max_size(); // A very large number6std::cout << l1.front(); // 1 (Returns reference to the first element)7//std::cout << l1.back(); // back() not supported8std::cout << l1.empty(); // 0 (false)9
10// The following won't work since std::sort() requires random access11// iterators, and std::list provides only bidirectional iterators.12//std::sort(l1.begin(), l1.end());13
14l1.sort();15
16auto it = std::find(l1.begin(), l1.end(), 3);17l1.insert(it, 10); // 1, 2, 10, 3, 4, 518l1.erase(it); // erase 3. now 1, 2, 10, 4, 5 ('it' becomes invalid) 19
20it = std::find(l1.begin(), l1.end(), 4);21l1.insert_after(it, 10); // 1, 2, 3, 10, 4, 10, 522l1.emplace_after(it, 100); // 1, 2, 3, 10, 4, 100, 10, 523l1.erase_after(it); // Erase the 100. 1, 2, 3, 10, 4, 10, 524
25// Lists are bi-directional, so iterators can iterate in both directions.26std::cout << *it; // 427it++;28std::cout << *it; // 529//it--; // Not supported30
31l1.resize(2); // 1, 232l1.resize(5); // 1, 2, 0, 0, 033
34l1.swap(l2); // Swaps the two deques
max_size(): Returns the maximum number of elements a vector can theoretically hold on the currentsystem. This is typically a very large number and depends on system and implementation limits.
91person p{"Kyungjae", 30};2std::deque<person> d;3
4//d.push_back(p); // Not supported5//d.pop_back(); // Not supported6d.push_front(person{"Sunny", 20});7d.pop_front(); // Remove element from the front8d.emplace_front("Yena", 5); // Construct the object in-place. Very efficient!9//d.emplace_back("Sunny", 20); // Not supportedL6: Creates a temporary (unnamed) person object and adds it to the forward list using move semantics.
L8: Constructs the person object directly in place using the constructor. Very efficient - no moves, no copies. It’s built exactly where it needs to be. Use this!
std::listEnsure that your custom classes provide the following three elements to work correctly with the STL:
Overloaded default constructor
Overloaded operator<
Overloaded operator==
test3() in the following code demonstrates the importance of defining a default constructor for your custom class.
1911234// std::advance()5
6class person7{8public:9 person() : name{"Unkown"}, age{0} {} // will be useful when resizing happens10 person(std::string name, int age)11 : name{name}, age{age}12 {}13 bool operator<(const person &rhs) const14 {15 return this->age < rhs.age;16 }17 bool operator==(const person &rhs) const 18 {19 return (this->name == rhs.name && this->age == rhs.age);20 }21 22private:23 friend std::ostream& operator<<(std::ostream &os, const person &p);24 std::string name;25 int age;26};27
28// Overloading the insertion operator as a global function.29std::ostream& operator<<(std::ostream &os, const person &p)30{31 os << p.name << ":" << p.age;32 return os;33}34
35// Template function to print elements of any list.36template <typename T>37void print(const std::list<T> &l)38{39 std::cout << "[ ";40 for (const auto &elem : l)41 {42 std::cout << elem << " ";43 }44 std::cout << "]" << std::endl;45}46
47// push_front(), push_back()48void test1(void)49{50 std::cout << "\nTEST1" << std::endl;51
52 std::list<int> l1{1, 2, 3, 4, 5};53 print(l1);54
55 // Very efficient when inserting at both ends.56 std::list<std::string> l2;57 l2.push_back("Back");58 l2.push_front("Front");59 print(l2);60
61 std::list<int> l3;62 l3 = {1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10};63 print(l3);64
65 std::list<int> l4(10, 100); // ten 100s in the list (using constructor)66 print(l4);67}68
69// size(), front(), back(), clear()70void test2(void)71{72 std::cout << "\nTEST2" << std::endl;73
74 std::list<int> l{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};75 print(l);76
77 std::cout << "Size: " << l.size() << std::endl;78
79 std::cout << "Front: " << l.front() << std::endl;80 std::cout << "Back: " << l.back() << std::endl;81
82 l.clear();83 print(l);84 std::cout << "Size: " << l.size() << std::endl;85}86
87void test3(void)88{89 std::cout << "\nTEST3" << std::endl;90
91 std::list<int> l1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};92 print(l1);93
94 l1.resize(5);95 print(l1);96
97 l1.resize(10); 98 print(l1);99
100 // This shows why it is important to define a overloaded default constructor101 // when using a custom class with the STL. (as well as 'operator<' and 102 // 'operator==')103 std::list<person> l2;104 l2.resize(5); // uses the person's overloaded default constructor105 print(l2);106}107
108void test4(void)109{110 std::cout << "\nTEST4" << std::endl;111
112 std::list<int> l1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};113 print(l1);114 auto it = std::find(l1.begin(), l1.end(), 5);115 if (it != l1.end())116 {117 l1.insert(it, 100); // insert a 100 before the iterator118 }119 print(l1);120
121 std::list<int> l2{1000, 2000, 3000};122 l2.insert(it, l2.begin(), l2.end()); // 'it' still referencing 5 in l1123 print(l1); // 1 2 3 4 100 1000 2000 3000 5 6 7 8 9 10124
125 std::advance(it, -4); // point to the 100126 std::cout << *it << std::endl;127
128 l1.erase(it); // remove the 100 - iterator becomes invalid129 // to use iterator again you need to reset it!130 print(l1);131}132
133// emplace(), emplace_back(), find()134void test5(void)135{136 std::cout << "\nTEST5" << std::endl;137
138 std::list<person> l{139 {"Kyungjae", 30},140 {"Sunny", 20},141 {"Yena", 5}142 };143
144 print(l);145 std::string name;146 int age{};147 std::cout << "\nEnter the name of the next person: ";148 getline(std::cin, name);149 std::cout << "Enter their age: ";150 std::cin >> age;151
152 // I'm not creating an object to add to the list. The list will create an153 // object for me based on the passed values.154 l.emplace_back(name, age);155 print(l);156
157 // Insert Nina before Yena158 auto it = std::find(l.begin(), l.end(), person{"Yena", 5});159 if (it != l.end())160 {161 l.emplace(it, "Nina", 1);162 }163 print(l);164}165
166// sort()167void test6(void)168{169 std::cout << "\nTEST6" << std::endl;170
171 std::list<person> l{172 {"Kyungjae", 30},173 {"Sunny", 20},174 {"Yena", 5}175 };176
177 print(l);178 l.sort(); // sort() will use the overloaded 'operator<' 179 print(l);180}181
182int main(int argc, char *argv[])183{184 test1();185 test2();186 test3();187 test4();188 test5();189 test6();190 return 0;191}381TEST12[ 1 2 3 4 5 ]3[ Front Back ]4[ 1 2 3 4 5 5 6 7 8 9 10 ]5[ 100 100 100 100 100 100 100 100 100 100 ]6
7TEST28[ 1 2 3 4 5 6 7 8 9 10 ]9Size: 1010Front: 111Back: 1012[ ]13Size: 014
15TEST316[ 1 2 3 4 5 6 7 8 9 10 ]17[ 1 2 3 4 5 ]18[ 1 2 3 4 5 0 0 0 0 0 ]19[ Unkown:0 Unkown:0 Unkown:0 Unkown:0 Unkown:0 ]20
21TEST422[ 1 2 3 4 5 6 7 8 9 10 ]23[ 1 2 3 4 100 5 6 7 8 9 10 ]24[ 1 2 3 4 100 1000 2000 3000 5 6 7 8 9 10 ]2510026[ 1 2 3 4 1000 2000 3000 5 6 7 8 9 10 ]27
28TEST529[ Kyungjae:30 Sunny:20 Yena:5 ]30
31Enter the name of the next person: Miyoung32Enter their age: 5033[ Kyungjae:30 Sunny:20 Yena:5 Miyoung:50 ]34[ Kyungjae:30 Sunny:20 Nina:1 Yena:5 Miyoung:50 ]35
36TEST637[ Kyungjae:30 Sunny:20 Yena:5 ]38[ Yena:5 Sunny:20 Kyungjae:30 ]