Descomponiendo la cadena en átomos: cómo recorrer palabras en C++ (sin volverse loco)
Imagina: estás escribiendo un analizador de logs, un analizador de comandos o simplemente quieres contar palabras en una oración. Lo primero que viene a la mente es tomar una cadena y recorrer cada palabra por separado. En Python esto se hace en una línea: "hello world".split(). Pero estamos en C++, así que la simplicidad es un lujo que hay que ganarse.
La pregunta "How do I iterate over the words of a string?" en Stack Overflow ha acumulado cientos de miles de visitas. Y no es casualidad: los principiantes se ahogan en los detalles del manejo de memoria, mientras que los expertos buscan el equilibrio entre velocidad y legibilidad. En este artículo, analizaremos 5 formas de iterar sobre palabras en C++, compararemos su rendimiento y entenderemos cuándo usar cada una.
Si alguna vez escribiste strtok y obtuviste un segfault, o intentaste insertar std::regex en un bucle crítico, este artículo es para ti.
Método #1: El clásico — std::istringstream
La forma más segura e intuitiva para principiantes. std::istringstream funciona como un flujo: simplemente lees palabras separadas por espacios.
#include <iostream>#include <sstream>#include <string>#include <vector>
int main() { std::string text = "C++ is not for the faint of heart"; std::istringstream stream(text); std::string word; std::vector<std::string> words; while (stream >> word) { words.push_back(word); std::cout << "Word: " << word << std::endl; } std::cout << "Total words: " << words.size() << std::endl; return 0;}Ventajas: código limpio, sin punteros sin procesar, gestión automática de memoria. Funciona con cualquier separador de espacio en blanco (tabulación, salto de línea).
Desventajas: más lento que los métodos manuales debido a la creación del flujo. No es adecuado para separadores personalizados (solo caracteres de espacio en blanco).
Cuándo usarlo: cuando la legibilidad es más importante que la velocidad. Ideal para ejemplos educativos y prototipos.
Método #2: Rápido y peligroso — std::strtok
Un legado de C que aún vive en producción. strtok modifica la cadena original (inserta caracteres nulos) y usa un búfer estático.
#include <iostream>#include <cstring>#include <vector>
int main() { char text[] = "Fast but dangerous — handle with care"; std::vector<char*> words; char* token = std::strtok(text, " "); while (token != nullptr) { words.push_back(token); std::cout << "Word: " << token << std::endl; token = std::strtok(nullptr, " "); } std::cout << "Total words: " << words.size() << std::endl; return 0;}Ventajas: muy rápido (funciona a nivel de cadenas C). Permite especificar cualquier conjunto de separadores.
Desventajas: no es thread-safe, destruye la cadena original, solo funciona con char*, no con std::string. Es fácil obtener comportamiento indefinido.
Cuándo usarlo: solo en bucles críticos donde cada nanosegundo cuenta y estás seguro de que es monohilo. En C++ moderno es mejor evitarlo.
Método #3: Recorrido manual — std::string::find y substr
A veces se necesita control total. El recorrido manual ofrece flexibilidad y no requiere bibliotecas adicionales.
#include <iostream>#include <string>#include <vector>
std::vector<std::string> splitManual(const std::string& text, char delimiter = ' ') { std::vector<std::string> tokens; size_t start = 0; size_t end = text.find(delimiter);