STL basics: vector and string
Functions and library types13 min readLesson 2 of 5
2.1 The standard library saves work
The standard template library (STL) is the part of the C++ standard library built from containers, iterators, and algorithms. You have already used two containers: std::vector and std::string. The <algorithm> header supplies operations such as sorting, searching, and counting.
These pieces work together. A vector provides iterators that mark a range, and an algorithm accepts that range. Learning the range convention lets you use one function with different containers.
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> scores = {72, 91, 64, 85};
std::sort(scores.begin(), scores.end());
for (int score : scores) {
std::cout << score << "\n";
}
return 0;
}Output
64 72 85 91
2.1.1 Vector operations
std::vector owns a contiguous block of elements and grows as needed. Useful operations include:
push_back(value)adds at the end.pop_back()removes the last element..size()reports the element count, and.empty()tells you whether the count is zero..front()and.back()read the ends..at(index)performs a bounds check..clear()removes every element.
Indexing is fast because the elements sit next to each other. Adding an element can move the whole block to a larger allocation, so references and iterators can be invalidated after growth.
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> ids = {11, 24, 37, 42, 24};
auto it = std::find(ids.begin(), ids.end(), 37);
if (it != ids.end()) {
std::cout << "Found at index " << (it - ids.begin()) << "\n";
}
std::cout << "Count of 24: " << std::count(ids.begin(), ids.end(), 24) << "\n";
return 0;
}Output
Found at index 2 Count of 24: 2
2.1.2 Strings as sequences
std::string manages a sequence of characters and provides the operations you expect: concatenation with +, appending with +=, .size(), indexing, .substr(), and .find().
find returns the position of the first match, or std::string::npos when no match exists. Always compare against npos before using the returned position. substr(start, length) creates a new string from part of the original; leaving out the length takes the rest of the string.
C++20 adds starts_with and ends_with for short string tests, and C++23 adds contains. Use them when your compiler and project target the matching standard. find remains available for earlier standards.
#include <iostream>
#include <string>
int main() {
std::string first = "C++";
std::string second = " notes";
std::string title = first + second;
title += "!";
std::cout << title << "\n";
std::cout << "Length: " << title.size() << "\n";
std::cout << "First letter: " << title[0] << "\n";
return 0;
}Output
C++ notes! Length: 10 First letter: C
2.1.3 Iterators and range loops
Iterators are values that point into a container. begin() marks the first element, and end() marks one past the last. Algorithms use a half-open range [begin, end). That convention lets an empty range have the same start and end.
Range-based loops hide the iterators: for (const std::string& name : names). Use auto for iterator variables when the type is long or obvious from context. auto it = scores.begin(); is clearer than spelling the full iterator type.
#include <iostream>
#include <string>
int main() {
std::string line = "name: Ravi";
auto pos = line.find(": ");
if (pos != std::string::npos) {
std::string value = line.substr(pos + 2);
std::cout << "Value: " << value << "\n";
}
std::cout << "Position: " << pos << "\n";
return 0;
}Output
Value: Ravi Position: 4
2.1.4 Algorithms replace hand-written loops
std::sort orders a range in place. std::find returns an iterator to the first matching value. std::count counts matches. std::accumulate adds values using an initial total.
Algorithm names describe the operation, and a short call can replace a loop that is easy to get wrong. Read the algorithm's requirements before using it, such as the iterator category and whether the range must be sorted.
2.1.5 When things invalidate
A vector's elements are stored in one block. When push_back needs more room, the vector allocates a larger block, copies or moves the elements, and frees the old block. Any iterator, pointer, or reference into the old block no longer refers to a valid element.
Do not hold a reference to an element and then grow the vector. Take the reference after growth, or use an index and look the element up again. The same rule applies when you erase elements while looping; use an algorithm or rebuild the container when the logic is complex.
#include <iostream>
#include <vector>
int main() {
std::vector<double> sales = {120.5, 90.0, 150.0};
double total = 0.0;
for (const double& sale : sales) {
total += sale;
}
std::cout << "Entries: " << sales.size() << "\n";
std::cout << "Average: " << total / sales.size() << "\n";
return 0;
}Output
Entries: 3 Average: 120.167
2.1.6 Common mistakes
- Forgetting
#include <algorithm>beforestd::sortorstd::find. - Passing
.size()where an iterator is expected. Algorithms takescores.begin(), scores.end(), notscores.size(). - Using a returned iterator after the vector has grown or elements have been erased.
- Using
nposwith a vector search orend()with a string search. String search returns a position, and vector search returns an iterator. - Modifying a string or vector while a range loop is using it.
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> pages = {12, 30, 18};
int total = std::accumulate(pages.begin(), pages.end(), 0);
std::cout << "Total pages: " << total << "\n";
return 0;
}Output
Total pages: 60
2.1.7 Practice
- Store five names in a vector, sort them, and print each on its own line.
- Read a sentence into a string and count the vowels with a range loop.
- Use
findto locate a value in a vector and print its index. - Split a
"key:value"string at the colon withfindandsubstr. - Compute the average of a vector of prices and read about
<iomanip>to control the decimal places.
