Visión general de la biblioteca estándar de C++
Aprende la biblioteca estándar de C++, incluyendo contenedores STL, algoritmos y componentes esenciales del desarrollo moderno.
La biblioteca estándar de C++ (incluyendo la STL) proporciona componentes eficientes, seguros y listos para usar, que incrementan significativamente la productividad: contendores, iteradores, algoritmos, cadenas de texto, flujos de E/S, utilidades de tiempo, sistema de archivos, concurrencia y tipos auxiliares. Este artículo resume las partes más importantes y ofrece ejemplos cortos y funcionales.
1) Estructura de encabezados e inclusión básica
La biblioteca estándar es modular. Incluir únicamente los encabezados necesarios es importante para el rendimiento y el tiempo de compilación.
<vector>,<array>,<list>,<deque><map>,<set>,<unordered_map>,<unordered_set><algorithm>,<numeric>,<iterator>,<ranges>(C++20)<string>,<string_view>,<regex><iostream>,<fstream>,<sstream><chrono>,<filesystem>,<random><memory>(smart pointers),<optional>,<variant>,<any><thread>,<mutex>,<future>,<condition_variable>
Compilación:
MSVC: cl /std:c++20 main.cpp
GCC/Clang: g++ -std=c++20 main.cpp -o app
2) Contenedores
Los contenedores almacenan datos, se recorren mediante iteradores y se procesan con algoritmos de la STL.
| Tipo | Ejemplos | Uso |
|---|---|---|
| Secuenciales | vector, array, deque, list | vector es la opción general; array para tamaño fijo. |
| Asociativos ordenados | map, set, multimap | Basados en árboles; búsqueda O(log n). |
| Asociativos no ordenados | unordered_map, unordered_set | Tablas hash; promedio O(1). |
| Pilas y colas | queue, priority_queue, stack | Procesamiento FIFO, LIFO o por prioridad. |
#include <vector>
#include <unordered_map>
#include <iostream>
using namespace std;
int main() {
vector<int> v; v.reserve(5);
v.emplace_back(3); v.emplace_back(1); v.emplace_back(2);
unordered_map<string,int> freq;
for (int x : v) freq[to_string(x)]++;
cout << "v size=" << v.size() << ", 2 freq=" << freq["2"] << "\n";
}
3) Iteradores y algoritmos
Los iteradores abstraen el acceso a los contenedores.
El encabezado <algorithm> proporciona operaciones genéricas independientes del contenedor.
#include <vector>
#include <algorithm>
#include <numeric>
#include <iostream>
using namespace std;
int main() {
vector<int> a{5,1,4,2,3};
sort(a.begin(), a.end());
int s = accumulate(a.begin(), a.end(), 0);
auto it = find(a.begin(), a.end(), 4);
if (it != a.end()) *it = 40;
transform(a.begin(), a.end(), a.begin(),
[](int x){ return x + 10; });
for (int x : a) cout << x << ' ';
}
4) Ranges en C++20 (breve)
Ranges permite encadenar algoritmos en estilo “pipeline”. Requiere soporte C++20.
#include <vector>
#include <ranges>
#include <iostream>
using namespace std;
int main() {
vector<int> v{1,2,3,4,5,6};
auto even_times10 = v
| views::filter([](int x){ return x%2==0; })
| views::transform([](int x){ return x*10; });
for (int x : even_times10) cout << x << ' ';
}
5) string, string_view y regex
std::string posee su propia memoria; std::string_view es una vista no propietaria (cuidado con el tiempo de vida).
<regex> sirve para expresiones regulares.
#include <string>
#include <string_view>
#include <regex>
#include <iostream>
using namespace std;
bool is_email(string_view s) {
static const regex re(R"((\w+)(\.\w+)*@(\w+)(\.\w+)+)");
return regex_match(s.begin(), s.end(), re);
}
int main() {
string name = "Ada Lovelace";
string_view view = name;
cout << view.substr(0, 3) << "\n";
cout << boolalpha << is_email("dev@example.com") << "\n";
}
6) Flujos de entrada/salida (iostream, fstream, sstream)
Los flujos se encadenan fácilmente con operadores.
fstream maneja archivos, stringstream facilita el análisis de texto.
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
ofstream out("data.txt");
out << "42, Modern C++\n"; out.close();
ifstream in("data.txt");
string line; getline(in, line);
stringstream ss(line);
int id; char comma; string title;
ss >> id >> comma; getline(ss, title);
cout << "id=" << id << " title=" << title << "\n";
}
7) Tiempo y duración (chrono)
<chrono> permite medir intervalos de tiempo y gestionar objetos temporales.
#include <chrono>
#include <iostream>
using namespace std;
int main() {
using namespace chrono;
auto t0 = steady_clock::now();
for (volatile int i=0;i<1000000;i++) {}
auto t1 = steady_clock::now();
cout << "ms=" << duration_cast<milliseconds>(t1 - t0).count() << "\n";
}
8) Sistema de archivos (filesystem)
Proporciona gestión multiplataforma de archivos y directorios.
Las versiones antiguas de GCC requerían -lstdc++fs; las modernas ya no.
#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = std::filesystem;
int main() {
for (const auto& e : fs::directory_iterator(".")) {
cout << e.path().filename().string() << "\n";
}
}
9) Números aleatorios (random)
C++ moderno utiliza el generador Mersenne Twister (mt19937) y distribuciones estadísticas.
#include <random>
#include <iostream>
using namespace std;
int main() {
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<int> dist(1, 6);
for (int i=0;i<5;i++) cout << dist(gen) << ' ';
}
10) Memoria y tipos auxiliares
<memory> incluye smart pointers (unique_ptr, shared_ptr, weak_ptr).
<optional> representa “valor o ninguno”, <variant> es una unión tipada,
<any> permite almacenar cualquier tipo (type-erasure).
#include <memory>
#include <optional>
#include <variant>
#include <iostream>
using namespace std;
optional<int> parse_pos_int(int x) { return x>=0 ? optional<int>(x) : nullopt; }
int main() {
auto p = make_unique<int>(42);
cout << *p << "\n";
if (auto v = parse_pos_int(-7)) cout << *v; else cout << "ninguno\n";
variant<int,string> v2 = 10; v2 = string("texto");
visit([](auto& t){ cout << t << "\n"; }, v2);
}
11) Concurrencia (thread, mutex, future)
Proporciona mecanismos básicos de ejecución multihilo y sincronización.
#include <thread>
#include <mutex>
#include <future>
#include <iostream>
using namespace std;
mutex m; int counter = 0;
void work(int n){
lock_guard<mutex> lk(m);
counter += n;
}
int main() {
thread t1(work, 1), t2(work, 2);
t1.join(); t2.join();
auto fut = async(launch::async, []{ return 40 + 2; });
cout << "counter=" << counter << " resultado=" << fut.get() << "\n";
}
12) Herramientas numéricas (numeric, cmath)
<numeric> ofrece acumulación y reducción; <cmath> proporciona funciones matemáticas estándar.
#include <vector>
#include <numeric>
#include <iostream>
using namespace std;
int main() {
vector<double> x{1.0, 2.0, 3.0};
double avg = accumulate(x.begin(), x.end(), 0.0) / x.size();
cout << "promedio=" << avg << "\n";
}
13) Referencia rápida (¿cuándo usar qué?)
- Contenedor general: vector
- Datos ordenados o búsqueda por rango: map/set
- Acceso rápido por hash: unordered_map/unordered_set
- Pipelines expresivos: ranges (C++20)
- Ficheros y directorios: filesystem
- Medición de tiempo: chrono
- Valor opcional seguro: optional; multivalor tipado: variant
14) TL;DR
- STL se basa en el trío: contenedores + iteradores + algoritmos.
- vector es la opción por defecto; map/set para datos ordenados, unordered_* para acceso rápido.
- algorithm/numeric permiten transformaciones genéricas; ranges (C++20) mejora la expresividad.
- string_view permite acceso sin copia (cuidado con la vida útil).
- chrono, filesystem, random simplifican tareas del sistema.
- Herramientas modernas: optional, variant, any, smart pointers.
- Para concurrencia: thread/mutex/future.
- Todos los ejemplos funcionan en Visual Studio 2022 y GCC 11+.