C++ Containers
Os containers (recipientes) da biblioteca padrão guardam coleções de valores: uma lista que cresce, um dicionário, um conjunto sem repetidos, uma pilha, uma fila. Esta página reúne os onze mais usados: qual cabeçalho incluir, quando usar cada um, quanto custa cada operação e os métodos principais, com exemplo e o resultado real (83 exemplos compilados e executados com o g++ 15.2, -std=c++23). Para aprender com calma, comece por O que é a STL e std::vector.
- Cada container tem uma declaração inicial (no título da tabela). Cada exemplo começa dela, do zero.
- Nos métodos que mudam o container, o resultado mostra como ele ficou, no formato do
std::println("{}", c)C++23:[10, 20]para sequências,{10, 20}para conjuntos,{"ana": 9}para mapas. - Nos
unordered_…, a ordem mostrada é a que saiu no laboratório; em outro compilador (até no editor do guia) pode ser outra. - Posições começam em 0.
begin()é um iterador para o primeiro elemento;end(), para "depois do último".
Atalhos: Visão geral · Complexidade · Qual usar · vector · array · deque · list · map · unordered_map · set · unordered_set · stack · queue · priority_queue
Exemplo rápido
#include <map>
#include <print>
#include <set>
#include <string>
#include <vector>
int main() {
std::vector<std::string> compras{"pão", "leite", "café", "leite"};
compras.push_back("ovos");
std::println("lista: {} ({} itens)", compras, compras.size());
std::set<std::string> semRepetir(compras.begin(), compras.end());
std::println("sem repetir: {}", semRepetir);
std::map<std::string, int> quantos;
for (const auto& item : compras) {
++quantos[item];
}
std::println("quantos: {}", quantos);
}
$ g++ -std=c++23 -Wall -Wextra colecoes.cpp -o colecoes
$ ./colecoes
lista: ["pão", "leite", "café", "leite", "ovos"] (5 itens)
sem repetir: {"café", "leite", "ovos", "pão"}
quantos: {"café": 1, "leite": 2, "ovos": 1, "pão": 1}
O mesmo item, três containers: o vector guarda tudo na ordem em que entrou (com o "leite" repetido), o set guarda cada um uma vez, em ordem, e o map associa cada item a um número. O set e o map ordenam comparando bytes, e por isso "pão" (com ã) veio depois de "ovos".
Experimente: qualquer exemplo das tabelas cabe aqui. Troque os itens, acrescente um std::deque ou uma std::stack e mostre com std::println.
#include <map>
#include <print>
#include <set>
#include <string>
#include <vector>
int main() {
std::vector<std::string> compras{"pão", "leite", "café", "leite"};
compras.push_back("ovos");
std::println("lista: {} ({} itens)", compras, compras.size());
std::set<std::string> semRepetir(compras.begin(), compras.end());
std::println("sem repetir: {}", semRepetir);
std::map<std::string, int> quantos;
for (const auto& item : compras) {
++quantos[item];
}
std::println("quantos: {}", quantos);
}
Visão geral
| Container | Cabeçalho | O que é | Por posição [i] | Ordem | Repetidos | Aula |
|---|---|---|---|---|---|---|
std::vector<T> | <vector> | Lista que cresce, elementos lado a lado na memória. | sim | a de inserção | sim | vector |
std::array<T, N> | <array> | Array de tamanho fixo, conhecido na compilação. | sim | a de inserção | sim | std::array |
std::deque<T> | <deque> | "Fila de duas pontas": cresce rápido nos dois lados. | sim | a de inserção | sim | list e deque |
std::list<T> | <list> | Lista ligada: cada elemento aponta para o vizinho. | não | a de inserção | sim | list e deque |
std::map<K, V> | <map> | Dicionário chave → valor, ordenado pela chave. | pela chave | crescente de chave | chaves não (multimap sim) | std::map |
std::unordered_map<K, V> | <unordered_map> | Dicionário com tabela de espalhamento (hash). | pela chave | nenhuma | chaves não | unordered_map |
std::set<T> | <set> | Conjunto ordenado, sem repetidos. | não | crescente | não (multiset sim) | std::set |
std::unordered_set<T> | <unordered_set> | Conjunto com hash, sem repetidos. | não | nenhuma | não | std::set |
std::stack<T> | <stack> | Pilha: o último que entra é o primeiro que sai. | não (só o topo) | — | sim | stack e queue |
std::queue<T> | <queue> | Fila: o primeiro que entra é o primeiro que sai. | não (só as pontas) | — | sim | stack e queue |
std::priority_queue<T> | <queue> | Fila em que sai sempre o maior (ou o menor). | não (só o topo) | — | sim | stack e queue |
stack, queue e priority_queue são adaptadores: por dentro usam um deque (ou um vector, no caso da priority_queue) e só mostram as operações permitidas. Por isso não têm begin()/end() e não dá para percorrê-los com for. Desde o C++23 existem também std::flat_map e std::flat_set (<flat_map>, <flat_set>), mapas e conjuntos ordenados guardados num vetor; o g++ 15 já os tem.
Complexidade
Quanto o tempo de cada operação cresce quando o container cresce (n = número de elementos). O(1): constante, não depende do tamanho. O(log n): cresce muito devagar (um milhão de elementos ≈ 20 passos). O(n): proporcional ao tamanho. "Amortizado": quase sempre O(1); de vez em quando, uma operação cara (o vector realocando) que, dividida por todas, some.
| Container | Acesso [i] | Inserir/remover no fim | No começo | No meio | Buscar um valor |
|---|---|---|---|---|---|
vector | O(1) | O(1) amortizado | O(n) | O(n) | O(n); O(log n) se ordenado (binary_search) |
array | O(1) | tamanho fixo: não insere nem remove | O(n) | ||
deque | O(1) | O(1) | O(1) | O(n) | O(n) |
list | — | O(1) | O(1) | O(1) com o iterador em mãos | O(n) |
map, set | pela chave: O(log n) | inserir e remover: O(log n), sempre no lugar certo da ordem | O(log n) | ||
unordered_map, unordered_set | pela chave: O(1) em média | inserir e remover: O(1) em média (O(n) no pior caso) | O(1) em média | ||
stack, queue | — | push, pop, top/front: O(1) | — | ||
priority_queue | — | top: O(1); push e pop: O(log n) | — | ||
Qual usar
| Você precisa de… | Use |
|---|---|
| Uma lista de coisas, na ordem, que cresce. (Na dúvida, é esta.) | std::vector |
| Um número fixo de elementos, sabido ao escrever o código (os 12 meses, as 3 notas). | std::array |
| Achar um valor pela chave (nome → telefone) e listar em ordem. | std::map |
| Achar pela chave o mais rápido possível, sem ligar para a ordem. | std::unordered_map |
| Saber se algo já apareceu; tirar repetidos. | std::set (ordenado) ou std::unordered_set |
| Desfazer (Ctrl+Z), conferir parênteses, voltar pelo caminho. | std::stack |
| Atender na ordem de chegada (fila do caixa, tarefas). | std::queue |
| Atender sempre o mais urgente primeiro. | std::priority_queue |
| Inserir e tirar muito nas duas pontas, com acesso por posição. | std::deque |
| Inserir e remover no meio sem invalidar os outros iteradores. | std::list (raramente: na prática o vector costuma ser mais rápido até nisso, por causa da memória contígua) |
std::vector · #include <vector> · Aula
Declaração inicial dos exemplos: std::vector<int> v{10, 20, 30};
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
size() · empty() | Quantos elementos; se está vazio. | v.size()v.empty() | 3false |
operator[](i) · at(i) | Elemento na posição i. [] não confere (fora do tamanho é comportamento indefinido); at confere e lança std::out_of_range. | v[1]v.at(5) | 20lança std::out_of_rangewhat(): vector::_M_range_check: __n (which is 5) >= this->size() (which is 3) |
front() · back() | Primeiro e último. | v.front()v.back() | 1030 |
push_back(x) · emplace_back(args…) C++11 | Acrescenta no fim. emplace_back constrói o elemento ali mesmo, com os argumentos do construtor. | v.push_back(40)v.emplace_back(50) | v = [10, 20, 30, 40]v = [10, 20, 30, 50] |
pop_back() | Tira o último. | v.pop_back() | v = [10, 20] |
insert(posição, x) | Insere antes da posição (um iterador). Empurra todos os seguintes: O(n). | v.insert(v.begin() + 1, 15)v.insert(v.begin(), 5) | v = [10, 15, 20, 30]v = [5, 10, 20, 30] |
erase(posição) · erase(início, fim) | Remove um elemento ou um trecho [início, fim). | v.erase(v.begin())v.erase(v.begin(), v.begin() + 2) | v = [20, 30]v = [30] |
std::erase(v, x) · std::erase_if(v, f) C++20 | Remove todos os iguais a x (ou que satisfazem f). Devolve quantos removeu. | std::erase(v, 20)std::erase_if(v, [](int x) { return x > 15; }) | v = [10, 30]v = [10] |
clear() · resize(n) | Esvazia; muda o tamanho (novos elementos valem 0). | v.clear()v.resize(5) | v = []v = [10, 20, 30, 0, 0] |
reserve(n) · capacity() | Reserva espaço; quanto cabe sem realocar. | v.reserve(100); v.capacity() | 100 |
std::ranges::contains(v, x) C++23 | Tem x? Busca linear, O(n). De <algorithm>. | std::ranges::contains(v, 20) | true |
std::ranges::sort(v) C++20 | Ordena (de <algorithm>); com std::greater{}, do maior para o menor. | std::ranges::sort(v, std::greater{}) | v = [30, 20, 10] |
std::array · #include <array> · Aula
Declaração inicial dos exemplos: std::array<int, 3> a{10, 20, 30};
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
size() C++11 | O tamanho, fixo, faz parte do tipo (<int, 3>). | a.size() | 3 |
operator[](i) · at(i) C++11 | Como no vector. | a[2]a.at(3) | 30lança std::out_of_rangewhat(): array::at: __n (which is 3) >= _Nm (which is 3) |
front() · back() C++11 | Primeiro e último. | a.back() | 30 |
fill(x) C++11 | Põe x em todas as posições. | a.fill(0) | a = [0, 0, 0] |
==, < C++11 | Compara elemento a elemento. | a == std::array<int, 3>{10, 20, 30} | true |
std::deque · #include <deque> · Aula
Declaração inicial dos exemplos: std::deque<int> d{10, 20, 30};
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
push_front(x) · push_back(x) | Acrescenta no começo ou no fim, ambos O(1). | d.push_front(5)d.push_back(40) | d = [5, 10, 20, 30]d = [10, 20, 30, 40] |
pop_front() · pop_back() | Tira do começo ou do fim. | d.pop_front() | d = [20, 30] |
operator[](i) · at(i) | Acesso por posição, O(1). | d[1] | 20 |
insert · erase · size · front · back | Como no vector. | d.insert(d.begin() + 1, 15) | d = [10, 15, 20, 30] |
std::list · #include <list> · Aula
Declaração inicial dos exemplos: std::list<int> l{30, 10, 20};
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
push_front(x) · push_back(x) · pop_front() · pop_back() | Pontas, O(1). | l.push_front(5)l.pop_back() | l = [5, 30, 10, 20]l = [30, 10] |
insert(posição, x) | Insere em O(1) se você já tem o iterador. Não há []: para chegar à posição, ande com std::next (O(n)). | l.insert(std::next(l.begin()), 15) | l = [30, 15, 10, 20] |
remove(x) · remove_if(f) | Remove todos os iguais a x. | l.remove(10) | l = [30, 20] |
sort() · reverse() · unique() | Métodos próprios (o std::sort não funciona em list). unique tira repetidos vizinhos. | l.sort()l.reverse() | l = [10, 20, 30]l = [20, 10, 30] |
front() · back() · size() | Primeiro, último, tamanho. | l.front()l.size() | 303 |
std::map · #include <map> · Aula
Declaração inicial dos exemplos: std::map<std::string, int> m{{"bia", 7}, {"ana", 9}};
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
operator[](chave) | Acessa o valor da chave. Se a chave não existe, cria (com valor 0) e devolve. | m["caio"] = 8m["ana"] = 10m["zé"]; m.size() | m = {"ana": 9, "bia": 7, "caio": 8}m = {"ana": 10, "bia": 7}3 |
at(chave) C++11 | Acessa sem criar: chave inexistente lança std::out_of_range. | m.at("bia")m.at("zé") | 7lança std::out_of_rangewhat(): map::at |
contains(chave) C++20 | A chave existe? | m.contains("ana")m.contains("zé") | truefalse |
find(chave) | Iterador para o par (->first = chave, ->second = valor), ou end() se não achar. | m.find("bia")->secondm.find("zé") == m.end() | 7true |
count(chave) | 0 ou 1 (no multimap, quantos). | m.count("ana") | 1 |
insert({chave, valor}) | Insere só se a chave não existe. Devolve um par (iterador, inseriu?). | m.insert({"ana", 0}).secondm.insert({"caio", 8}) | falsem = {"ana": 9, "bia": 7, "caio": 8} |
insert_or_assign(chave, valor) C++17 | Insere ou substitui. | m.insert_or_assign("ana", 0) | m = {"ana": 0, "bia": 7} |
erase(chave) | Remove pela chave; devolve quantos removeu. | m.erase("ana") | m = {"bia": 7} |
for (auto& [chave, valor] : m) C++17 | Percorre em ordem crescente de chave. | m.begin()->first | "ana" |
std::unordered_map · #include <unordered_map> · Aula
Declaração inicial dos exemplos: std::unordered_map<std::string, int> u{{"bia", 7}, {"ana", 9}};
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
operator[] · at · contains · find · count · insert · erase C++11 | Os mesmos métodos do map, com o mesmo comportamento (o [] também cria). A diferença: busca O(1) em média e nenhuma ordem. | u["caio"] = 8u.at("ana")u.contains("zé") | u = {"caio": 8, "ana": 9, "bia": 7}9false |
bucket_count() · load_factor() C++11 | Quantas “gavetas” a tabela de espalhamento tem e quão cheias estão, em média. | u.bucket_count() | 13 |
Repare que "caio" apareceu antes dos outros: num unordered_map a ordem é a das "gavetas" internas, e pode mudar quando a tabela cresce.
std::set · #include <set> · Aula
Declaração inicial dos exemplos: std::set<int> s{30, 10, 20};
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
insert(x) | Insere, se ainda não existe. Mantém em ordem. Devolve (iterador, inseriu?). | s.insert(15)s.insert(10).second | s = {10, 15, 20, 30}false |
contains(x) · count(x) C++20 | Existe? | s.contains(20)s.count(99) | true0 |
erase(x) | Remove. | s.erase(10) | s = {20, 30} |
begin() · rbegin() | O menor e o maior (ordenado). | *s.begin()*s.rbegin() | 1030 |
lower_bound(x) · upper_bound(x) | Primeiro elemento ≥ x; primeiro > x. | *s.lower_bound(15)*s.upper_bound(20) | 2030 |
std::unordered_set · #include <unordered_set> · Aula
Declaração inicial dos exemplos: std::unordered_set<int> us{30, 10, 20};
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
insert · contains · count · erase · size C++11 | Como o set, sem ordem, com busca O(1) em média. | us.insert(15)us.contains(10)us.erase(30) | us = {15, 20, 10, 30}trueus = {20, 10} |
std::stack · #include <stack> · Aula
Declaração inicial dos exemplos: std::stack<int> p; p.push(10); p.push(20); p.push(30);
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
push(x) · emplace(args…) | Empilha no topo. | p.push(40) | p = [10, 20, 30, 40] |
top() | Olha o topo (o último que entrou), sem tirar. | p.top() | 30 |
pop() | Tira o topo. Não devolve nada: leia com top() antes. | p.pop() | p = [10, 20] |
size() · empty() | Tamanho; vazia? | p.size() | 3 |
O println mostra a pilha de baixo para cima: o último número é o topo.
std::queue · #include <queue> · Aula
Declaração inicial dos exemplos: std::queue<int> f; f.push(10); f.push(20); f.push(30);
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
push(x) | Entra no fim da fila. | f.push(40) | f = [10, 20, 30, 40] |
front() · back() | O primeiro (o próximo a sair) e o último. | f.front()f.back() | 1030 |
pop() | Tira o da frente (não devolve). | f.pop() | f = [20, 30] |
size() · empty() | Tamanho; vazia? | f.empty() | false |
O println mostra a fila da frente para o fim: o primeiro número é o próximo a sair.
std::priority_queue · #include <queue> · Aula
Declaração inicial dos exemplos: std::priority_queue<int> pq; pq.push(20); pq.push(50); pq.push(10);
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
top() | O maior elemento (por padrão). | pq.top() | 50 |
push(x) · pop() | Insere; tira o maior. Ambos O(log n). | pq.pop(); pq.top()pq.push(30); pq.top() | 2050 |
priority_queue<T, vector<T>, greater<T>> | Fila de prioridade do menor. | std::priority_queue<int, std::vector<int>, std::greater<int>> menor; menor.push(20); menor.push(50); menor.push(10);menor.top() | 10 |
Só o topo é acessível. Para ver todos em ordem, tire um por um com top() e pop().
Depois de um push_back, insert ou erase num vector, iteradores, ponteiros e referências para os elementos podem ficar inválidos (o vetor pode ter mudado de lugar na memória). Usá-los é comportamento indefinido. Não guarde &v[0] ou v.begin() e depois acrescente elementos. map, set e list não têm esse problema (só o elemento apagado fica inválido).
Missão: a Ana lançou as notas da turma num vector. Mostre as notas diferentes, em ordem crescente, separadas por espaço, e quantas são. Dica: um container desta página faz as duas coisas sozinho, e ele pode ser criado direto do vetor: C diferentes(notas.begin(), notas.end());.
7 9 10 3 notas diferentes
#include <iostream>
#include <vector>
int main() {
std::vector<int> notas{7, 9, 7, 10, 9, 7};
// seu código aqui
}
#include <iostream>
#include <set>
#include <vector>
int main() {
std::vector<int> notas{7, 9, 7, 10, 9, 7};
std::set<int> diferentes(notas.begin(), notas.end());
for (int n : diferentes) {
std::cout << n << ' ';
}
std::cout << '\n' << diferentes.size() << " notas diferentes\n";
}