C++ Containers
STL containers for storing and managing data collections
📦 What are Containers?
Containers are STL classes that store collections of objects. They provide different ways to organize data with built-in functions for insertion, deletion, and access operations.
#include <vector>
using namespace std;
vector<int> numbers = {10, 20, 30};
numbers.push_back(40);
cout << "Size: " << numbers.size();
Output:
Size: 4
Container Categories
Sequence Containers
Sequence containers store elements in a strict linear order, allowing positional access. C++ offers
std::vector for dynamic arrays, std::list for doubly-linked lists, and
std::deque for double-ended queues. Each has distinct performance traits: vectors enable fast random
access, lists excel at insertions/deletions anywhere, and deques allow efficient front/back operations. Choosing the
right container depends on your access patterns and modification needs.
Associative Containers
Sorted key-based storage
Container Adapters
Container adapters provide specialized interfaces for common data structures like stacks, queues, and
priority queues. They wrap underlying sequence containers (e.g., std::deque or
std::vector) to enforce specific access rules. A stack (std::stack) follows LIFO (Last-In,
First-Out), a queue (std::queue) follows FIFO (First-In, First-Out), and a priority queue
(std::priority_queue) orders elements by priority. They simplify implementation of standard data
patterns.
Unordered Containers
Hash-based fast access
🔹 Sequence Containers
Sequence containers store elements in a strict linear order, allowing positional access. C++ offers
std::vector for dynamic arrays, std::list for doubly-linked lists, and
std::deque for double-ended queues. Each has distinct performance traits: vectors enable fast random
access, lists excel at insertions/deletions anywhere, and deques allow efficient front/back operations. Choosing the
right container depends on your access patterns and modification needs.
#include <iostream>
#include <vector>
#include <list>
#include <deque>
using namespace std;
int main() {
// Vector - dynamic array
vector<int> vec = {1, 2, 3};
vec.push_back(4);
cout << "Vector[0]: " << vec[0] << endl;
// List - doubly linked list
list<string> lst = {"apple", "banana"};
lst.push_front("orange");
cout << "List size: " << lst.size() << endl;
// Deque - double-ended queue
deque<int> dq = {10, 20};
dq.push_front(5);
dq.push_back(30);
cout << "Deque front: " << dq.front() << endl;
return 0;
}
Output:
Vector[0]: 1
List size: 3
Deque front: 5
🔹 Container Adapters
Container adapters provide specialized interfaces for common data structures like stacks, queues, and
priority queues. They wrap underlying sequence containers (e.g., std::deque or
std::vector) to enforce specific access rules. A stack (std::stack) follows LIFO (Last-In,
First-Out), a queue (std::queue) follows FIFO (First-In, First-Out), and a priority queue
(std::priority_queue) orders elements by priority. They simplify implementation of standard data
patterns.
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
int main() {
// Stack - LIFO (Last In, First Out)
stack<int> stk;
stk.push(10);
stk.push(20);
stk.push(30);
cout << "Stack top: " << stk.top() << endl;
stk.pop();
cout << "After pop: " << stk.top() << endl;
// Queue - FIFO (First In, First Out)
queue<string> q;
q.push("first");
q.push("second");
q.push("third");
cout << "Queue front: " << q.front() << endl;
q.pop();
cout << "After pop: " << q.front() << endl;
return 0;
}
Output:
Stack top: 30
After pop: 20
Queue front: first
After pop: second
🔹 Common Container Operations
Most C++ containers share a set of common member functions for basic management. These include
size() to get element count, empty() to check if the container is empty,
front() and back() to access ends, and clear() to remove all elements.
Iterators like begin() and end() enable range traversal. Understanding these universal
operations ensures consistent and portable code across different container types.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> container = {10, 20, 30};
// Size operations
cout << "Size: " << container.size() << endl;
cout << "Empty: " << (container.empty() ? "Yes" : "No") << endl;
// Access operations
cout << "First element: " << container.front() << endl;
cout << "Last element: " << container.back() << endl;
// Modification operations
container.push_back(40);
container.pop_back();
// Iteration
cout << "Elements: ";
for(auto element : container) {
cout << element << " ";
}
cout << endl;
// Clear all elements
container.clear();
cout << "After clear, size: " << container.size() << endl;
return 0;
}
Output:
Size: 3
Empty: No
First element: 10
Last element: 30
Elements: 10 20 30
After clear, size: 0
🔹 Choosing the Right Container
Select containers based on your specific needs:
When to use each container:
- vector: Random access, dynamic size, frequent back insertions
- list: Frequent insertions/deletions in middle, no random access needed
- deque: Insertions/deletions at both ends
- stack: LIFO operations (undo functionality, expression evaluation)
- queue: FIFO operations (task scheduling, breadth-first search)