Home | Projects | Notes > C++ Programming > Sequence Container - std::vector
std::vector
std::vectorDeclared in the <vector> header file.
Dynamic size
Can expand and contract as needed which is handled automatically by the STL.
Elements are stored in continguous memory, like an array.
As the std::vector expands a new larger area in memory is allocated and the current elements are moved to it.
Direct element access - Constant time: O(1)
Rapid insertion and deletion at the back - Constant time: O(1)
Insertion or deletion of elements (elsewhere) - Linear time: O(n)
All iterators are available but may become invalid.
Iterator invalidation can occur when a std::vector resizes and allocates new memory to accommodate additional elements.
131// Initialization2std::vector<int> v1{1, 2, 3, 4, 5};3std::vector<int> v2(10, 500); // ten 500s4
5// Initialization6std::vector<std::string> v2{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 list13v1 = {2, 4, 6, 8, 10};For more information, see cppreference.com.
x
1std::vector<int> v1{1, 2, 3, 4, 5};2std::vector<int> v2{10, 20, 30, 40, 50};3
4std::cout << v1.size(); // 55std::cout << v1.capacity(); // 56std::cout << v1.max_size(); // A very large number7std::cout << v1.at(0); // 1 (Supports out-of-bounds check)8std::cout << v1[1]; // 2 (Does not support out-of-bounds check)9std::cout << v1.front(); // 1 (Returns reference to the first element)10std::cout << v1.back(); // 5 (Returns reference to the last element)11std::cout << v1.empty(); // 0 (false)12
13std::sort(v1.begin(), v1.end());14
15auto it = std::find(v1.begin(), v1.end(), 3);16v1.insert(it, 10); // 1, 2, 10, 3, 4, 517
18it = std::find(v1.begin(), v1.end(), 4);19v1.insert(it, v2.begin(), v2.end());20 // 1, 2, 10, 3, 10, 20, 30, 40, 50, 4, 521
22v1.swap(v2); // Swaps the two vectors
capacity(): Returns the number of elements the vector can hold before needing to allocate more memory. When this capacity is exceeded, the vector expands dynamically.
max_size(): Returns the maximum number of elements a vector can theoretically hold on the current system. This is typically a very large number and depends on system and implementation limits.
71person p{"Kyungjae", 30};2std::vector<person> v;3
4v.push_back(p); // Add p to the back (copy is made)5v.pop_back(); // Remove the last element (p in this case)6v.push_back(person{"Yena", 5}); // Add a temporary object using move semantics7v.emplace_back("Sunny", 20); // Construct the object in-place. Very efficient!L4: Remember, all standard container classes store copies of the elements they hold. So in this case, a copy of
pis made.L6: Creates a temporary (unnamed) person object and adds it to the vector using move semantics.
L7: 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::array3281234
5class person6{7public:8 person() = default;9 person(std::string name, int age)10 : name{name}, age{age}11 {}12 // When using the STL with your custom class, always ensure that you 13 // overload `operator<` and `operator==`, as they are commonly used by14 // STL algorithms and containers.15 bool operator<(const person &rhs) const16 {17 return this->age < rhs.age;18 }19 bool operator==(const person &rhs) const 20 {21 return (this->name == rhs.name && this->age == rhs.age);22 }23 24private:25 friend std::ostream& operator<<(std::ostream &os, const person &p);26 std::string name;27 int age;28};29
30// Overloading the insertion operator as a global function.31std::ostream& operator<<(std::ostream &os, const person &p)32{33 os << p.name << ":" << p.age;34 return os;35}36
37// Using for_each() and a lambda expression to print elements.38void print1(const std::vector<int> &v)39{40 std::cout << "[ ";41 std::for_each(v.begin(), v.end(), [](int n) { std::cout << n << " "; });42 std::cout << "]" << std::endl;43}44
45// Template function to print elements of any vector.46template <typename T>47void print2(const std::vector<T> &v)48{49 std::cout << "[ ";50 for (const auto &elem : v)51 std::cout << elem << " ";52 std::cout << "]" << std::endl;53}54
55void test1(void)56{57 std::cout << "\nTEST1" << std::endl;58 59 std::vector<int> v{1, 2, 3, 4, 5};60 print1(v);61
62 v = {2, 4, 5, 6}; // assignment using an initialization list63 print2(v);64
65 std::vector<int> v1(10, 100); // ten 100s in the vector66 // Note: This is not an initialization list. We are calling the67 // overloaded constructor defined by the std::vector container.68 print2(v1);69}70
71// size(), max_size(), capacity(), shrink_to_fit(), reserve()72void test2(void)73{74 std::cout << "\nTEST2" << std::endl;75
76 std::vector<int> v{1, 2, 3, 4, 5};77
78 print1(v);79 std::cout << "\nv size: " << v.size() << std::endl;80 std::cout << "v max size: " << v.max_size() << std::endl;81 std::cout << "v capacity: " << v.capacity() << std::endl;82
83 // Typically when a vector exceeds its capacity, it will double its84 // capacity.85 v.push_back(6);86 print1(v);87 std::cout << "\nv size: " << v.size() << std::endl;88 std::cout << "v max size: " << v.max_size() << std::endl;89 std::cout << "v capacity: " << v.capacity() << std::endl;90
91 // shrink_to_fit() will shrink the amount of storage allocated to exactly92 // the vector size.93 v.shrink_to_fit(); // C++1194 print2(v);95 std::cout << "\nv size: " << v.size() << std::endl;96 std::cout << "v max size: " << v.max_size() << std::endl;97 std::cout << "v capacity: " << v.capacity() << std::endl;98
99 // reserve() will reserve a specified amount of storage. The capacity will100 // be adjusted to the passed value.101 v.reserve(100);102 print2(v);103 std::cout << "\nv size: " << v.size() << std::endl;104 std::cout << "v max size: " << v.max_size() << std::endl;105 std::cout << "v capacity: " << v.capacity() << std::endl;106}107
108// [], at()109void test3(void)110{111 std::cout << "\nTEST3" << std::endl;112
113 std::vector<int> v{1, 2, 3, 4, 5};114 print1(v);115
116 v[0] = 100; // does NOT provide out-of-bounds check117 v.at(1) = 200; // provides out-of-bounds check118
119 print2(v);120}121
122// push_back(), emplace_back()123void test4(void)124{125 std::cout << "\nTEST4" << std::endl;126 std::vector<person> v;127
128 person p1{"Kyungjae", 30};129 print2(v);130
131 v.push_back(p1);132 print2(v);133
134 v.push_back(person{"Sunny", 20}); // temporary object, move semantics135 print2(v);136 137 // Pass the argument we would've passed into the constructor. emplace_back()138 // will call the constructor for us and put the element at the back.139 v.emplace_back("Yena", 5); // very efficient! highly recommended!140 print2(v);141}142
143// front(), back(), pop_back()144void test5(void)145{146 std::cout << "\nTEST5" << std::endl;147
148 std::vector<person> v{149 {"Kyungjae", 30},150 {"Sunny", 20},151 {"Yena", 5}152 };153
154 print2(v);155 std::cout << "\nFront: " << v.front() << std::endl;156 std::cout << "Back: " << v.back() << std::endl;157
158 v.pop_back(); // removing the last element from a vector is O(1)159 print2(v);160}161
162// clear(), erase()163void test6(void)164{165 std::cout << "\nTEST6" << std::endl;166
167 std::vector<int> v{1, 2, 3, 4, 5};168 print1(v);169
170 v.clear(); // remove all elements171 print1(v);172
173 v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// assignment using initialization list174 print1(v);175 v.erase(v.begin(), v.begin() + 2); // remove a subset of elements176 print1(v);177
178 v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// assignment using initialization list179 // erase all even numbers180 auto it = v.begin();181 while (it != v.end())182 {183 if (*it % 2 == 0)184 {185 v.erase(it);186 }187 else188 {189 it++; // only increment if not erased!190 }191 }192
193 print1(v);194}195
196// swap()197void test7(void)198{199 std::cout << "\nTEST7" << std::endl;200 201 std::vector<int> v1{1, 2, 3, 4, 5};202 std::vector<int> v2{10, 20, 30, 40, 50};203
204 print1(v1);205 print1(v2);206 std::cout << std::endl;207
208 // To use swap, the continers must store data of the same type, but their209 // size can be different.210 v2.swap(v1);211 print1(v1);212 print1(v2);213}214
215// sort()216void test8(void)217{218 std::cout << "\nTEST8" << std::endl;219
220 std::vector<int> v{1, 32, 3, 50, 14};221
222 print1(v);223 std::sort(v.begin(), v.end());224 print1(v);225
226 // Note that the reverse() can be used to sort a vector in reverse order.227}228
229// copy(), copy_if(), back_inserter()230void test9(void)231{232 std::cout << "\nTEST9" << std::endl;233
234 // std::back_inserter constructs a back-insert iterator that inserts new235 // elements at the end of the container it is applied to. It's a special236 // type of output iterator and is very efficient!237 // There's also std::front_inserter, which can be used with containers like238 // std::deque and std::list.239
240 // Copy one list to another using an iterator and std::back_inserter.241
242 std::vector<int> v1{1, 2, 3, 4, 5};243 std::vector<int> v2{10, 20};244
245 print1(v1);246 print1(v2);247 std::cout << std::endl;248
249 // Copy the entire v1 and insert it to the end of v2.250 std::copy(v1.begin(), v1.end(), std::back_inserter(v2));251 print1(v1);252 print1(v2);253 std::cout << std::endl;254
255 // copy_if() the eGement is even256 v1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};257 v2 = {10, 20};258
259 print1(v1);260 print1(v2);261 std::cout << std::endl;262
263 // Use the following in the coding assessment. You'll get the job!264 std::copy_if(v1.begin(), v1.end(), std::back_inserter(v2),265 [](int n) { return n % 2 == 0; }); // even only!266 print1(v1);267 print1(v2);268}269
270// transform()271void test10(void)272{273 std::cout << "\nTEST10" << std::endl;274
275 // Transform over 2 ranges.276 std::vector<int> v1{1, 2, 3, 4, 5};277 std::vector<int> v2{10, 20, 30, 40, 50};278 std::vector<int> v3;279 280 // 1*10, 2*20, 3*30, 4*40, 5*50 and store the results in v3.281 std::transform(v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3),282 [](int n1, int n2) { return n1 * n2; });283 284 print1(v3); 285}286
287// find(), insert()288void test11(void)289{290 std::cout << "\nTEST11" << std::endl;291
292 // Insert v2 into v1 before the element 5.293 std::vector<int> v1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};294 std::vector<int> v2{100, 200, 300, 400};295 296 print1(v1); 297 print1(v2); 298 std::cout << std::endl;299
300 auto it = std::find(v1.begin(), v1.end(), 5);301 if (it != v1.end())302 {303 std::cout << "Inserting..." << std::endl;304 v1.insert(it, v2.begin(), v2.end());305 }306 else307 {308 std::cout << "Error: 5 not found." << std::endl;309 }310
311 print1(v1);312}313
314int main(int argc, char *argv[])315{316 test1();317 test2();318 test3();319 test4();320 test5();321 test6();322 test7();323 test8();324 test9();325 test10();326 test11();327 return 0;328}851
2TEST13[ 1 2 3 4 5 ]4[ 2 4 5 6 ]5[ 100 100 100 100 100 100 100 100 100 100 ]6
7TEST28[ 1 2 3 4 5 ]9
10v size: 511v max size: 230584300921369395112v capacity: 513[ 1 2 3 4 5 6 ]14
15v size: 616v max size: 230584300921369395117v capacity: 1018[ 1 2 3 4 5 6 ]19
20v size: 621v max size: 230584300921369395122v capacity: 623[ 1 2 3 4 5 6 ]24
25v size: 626v max size: 230584300921369395127v capacity: 10028
29TEST330[ 1 2 3 4 5 ]31[ 100 200 3 4 5 ]32
33TEST434[ ]35[ Kyungjae:30 ]36[ Kyungjae:30 Sunny:20 ]37[ Kyungjae:30 Sunny:20 Yena:5 ]38
39TEST540[ Kyungjae:30 Sunny:20 Yena:5 ]41
42Front: Kyungjae:3043Back: Yena:544[ Kyungjae:30 Sunny:20 ]45
46TEST647[ 1 2 3 4 5 ]48[ ]49[ 1 2 3 4 5 6 7 8 9 10 ]50[ 3 4 5 6 7 8 9 10 ]51[ 1 3 5 7 9 ]52
53TEST754[ 1 2 3 4 5 ]55[ 10 20 30 40 50 ]56
57[ 10 20 30 40 50 ]58[ 1 2 3 4 5 ]59
60TEST861[ 1 32 3 50 14 ]62[ 1 3 14 32 50 ]63
64TEST965[ 1 2 3 4 5 ]66[ 10 20 ]67
68[ 1 2 3 4 5 ]69[ 10 20 1 2 3 4 5 ]70
71[ 1 2 3 4 5 6 7 8 9 10 ]72[ 10 20 ]73
74[ 1 2 3 4 5 6 7 8 9 10 ]75[ 10 20 2 4 6 8 10 ]76
77TEST1078[ 10 40 90 160 250 ]79
80TEST1181[ 1 2 3 4 5 6 7 8 9 10 ]82[ 100 200 300 400 ]83
84Inserting...85[ 1 2 3 4 100 200 300 400 5 6 7 8 9 10 ]