C++ Programming Tutorial
Learn modern C++ step-by-step — from basics to advanced features like templates, STL, and smart pointers. Clear explanations with practical, runnable examples.
C++ Standard Template Library (STL)
The STL provides a rich collection of containers, algorithms, and iterators that work together seamlessly. Using the STL means writing less code, fewer bugs, and better performance than hand-rolled data structures.
Sequence Containers
sequence.cpp
#include <iostream>
#include <vector>
#include <deque>
#include <list>
#include <array>
int main() {
// vector — dynamic array (most used container)
std::vector<int> vec{1, 2, 3, 4, 5};
vec.push_back(6);
vec.pop_back();
std::cout << "vec size: " << vec.size() << "
";
// deque — double-ended queue (fast insert at both ends)
std::deque<int> dq{10, 20, 30};
dq.push_front(5);
dq.push_back(40);
// list — doubly linked list (fast insert/remove anywhere)
std::list<int> lst{1, 2, 3};
lst.push_front(0);
lst.remove(2); // remove all elements with value 2
// array — fixed-size (compile-time size)
std::array<int, 4> arr{10, 20, 30, 40};
std::cout << "arr[2]: " << arr[2] << "
";
return 0;
}Associative Containers
associative.cpp
#include <iostream>
#include <map>
#include <unordered_map>
#include <set>
int main() {
// map — ordered key-value pairs (red-black tree, O(log n))
std::map<std::string, int> ages;
ages["Alice"] = 30;
ages["Bob"] = 25;
ages.insert({"Charlie", 35});
for (const auto& [name, age] : ages) { // structured bindings (C++17)
std::cout << name << ": " << age << "
";
} // sorted by key: Alice, Bob, Charlie
// Check if key exists
if (ages.count("Alice")) {
std::cout << "Alice found: " << ages["Alice"] << "
";
}
// unordered_map — hash table (O(1) average)
std::unordered_map<std::string, double> prices;
prices["apple"] = 1.50;
prices["banana"] = 0.75;
// set — unique sorted values
std::set<int> unique_nums{5, 3, 1, 4, 1, 3}; // stores: {1, 3, 4, 5}
for (int n : unique_nums) std::cout << n << " ";
std::cout << "
";
return 0;
}Algorithms
algorithms.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
int main() {
std::vector<int> v{5, 2, 8, 1, 9, 3, 7, 4, 6};
// Sort
std::sort(v.begin(), v.end()); // ascending
// std::sort(v.begin(), v.end(), std::greater<>()); // descending
// Find
auto it = std::find(v.begin(), v.end(), 7);
if (it != v.end()) {
std::cout << "Found 7 at index " << (it - v.begin()) << "
";
}
// Count
int count = std::count_if(v.begin(), v.end(), [](int x) { return x > 5; });
std::cout << "Numbers > 5: " << count << "
";
// Transform (in-place: double each element)
std::transform(v.begin(), v.end(), v.begin(), [](int x) { return x * 2; });
// Accumulate (sum)
int sum = std::accumulate(v.begin(), v.end(), 0);
std::cout << "Sum: " << sum << "
";
// Min/Max
auto [min_it, max_it] = std::minmax_element(v.begin(), v.end());
std::cout << "Min: " << *min_it << ", Max: " << *max_it << "
";
// Remove-erase idiom (remove even numbers)
v.erase(std::remove_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; }), v.end());
// For each
std::for_each(v.begin(), v.end(), [](int x) { std::cout << x << " "; });
std::cout << "
";
return 0;
}Container Comparison
| Container | Access | Insert/Remove | Ordered | Use When |
|---|---|---|---|---|
vector | O(1) random | O(1) back, O(n) middle | Insertion order | Default choice, contiguous memory |
deque | O(1) random | O(1) front/back | Insertion order | Need fast push_front |
list | O(n) sequential | O(1) anywhere (with iterator) | Insertion order | Frequent mid-list insert/remove |
map | O(log n) | O(log n) | Sorted by key | Ordered key-value, range queries |
unordered_map | O(1) avg | O(1) avg | No | Fast lookup by key (hash table) |
set | O(log n) | O(log n) | Sorted | Unique sorted values |
Iterators
iterators.cpp
#include <iostream>
#include <vector>
int main() {
std::vector<int> v{10, 20, 30, 40, 50};
// Iterator-based loop (how algorithms work internally)
for (auto it = v.begin(); it != v.end(); ++it) {
std::cout << *it << " ";
}
std::cout << "
";
// Reverse iteration
for (auto it = v.rbegin(); it != v.rend(); ++it) {
std::cout << *it << " "; // 50 40 30 20 10
}
std::cout << "
";
// const iterators (read-only)
for (auto it = v.cbegin(); it != v.cend(); ++it) {
std::cout << *it << " ";
// *it = 0; // ERROR: const iterator
}
return 0;
}Best Practices
- Default to
std::vector— cache-friendly, fastest for most workloads. - Use algorithms over raw loops —
std::sort,std::find,std::transformare well-tested and optimized. - Use
unordered_mapovermapwhen you do not need ordered keys — O(1) vs O(log n). - Use range-based for (
for (auto& x : container)) when you do not need the iterator itself. - Use structured bindings (C++17) for cleaner map/pair iteration.
- Reserve vector capacity (
v.reserve(n)) when you know the approximate size upfront.
Keep Practicing
Use the online compiler to run every example and experiment with modifications. The best way to learn C++ is by writing code — even small programs build strong foundations.