Documentos de Académico
Documentos de Profesional
Documentos de Cultura
os nuevos programadores suelen dedicar mucho tiempo a escribir bucles personalizados para realizar
tareas relativamente sencillas, como clasificar, contar o buscar matrices. Estos bucles pueden ser
problemáticos, tanto en términos de lo fácil que es cometer un error como en términos de mantenimiento
general, ya que los bucles pueden ser difíciles de entender.
Debido a que buscar, contar y ordenar son operaciones comunes, la biblioteca estándar de C++ viene con
un montón de funciones para hacer estas cosas en solo unas pocas líneas de código. Además, estas
funciones de biblioteca estándar vienen probadas previamente, son eficientes, funcionan en una variedad
de diferentes tipos de contenedores y muchas admiten la paralelización (la capacidad de dedicar múltiples
subprocesos de CPU a la misma tarea para completarla más rápido).
#include <algorithm>
#include <array>
#include <iostream>
int main()
{
std::array arr{ 13, 90, 99, 5, 40, 80 };
std::cout << "Enter a value to search for and replace with: ";
int search{};
int replace{};
std::cin >> search >> replace;
// std::find returns an iterator pointing to the found element (or the end of the container)
// we'll store it in a variable, using type inference to deduce the type of
// the iterator (since we don't care)
auto found{ std::find(arr.begin(), arr.end(), search) };
// Algorithms that don't find what they were looking for return the end iterator.
// We can access it by using the end() member function.
if (found == arr.end())
{
std::cout << "Could not find " << search << '\n';
}
else
{
// Override the found element.
*found = replace;
}
return 0;
}
COPIAR
Ejemplo de ejecución cuando se encuentra el elemento
13 90 99 234 40 80
No se pudo encontrar 0
13 90 99 5 40 80
A veces queremos ver si hay un valor en un contenedor que coincida con alguna condición (por ejemplo,
una cadena que contiene una subcadena específica) en lugar de un valor exacto. En tales
casos, std::find_ifes perfecto.
La std::find_iffunción funciona de manera similar a std::find, pero en lugar de pasar un valor específico
para buscar, pasamos un objeto invocable, como un puntero de función (o una lambda, que veremos más
adelante). Para cada elemento que se itera, std::find_ifllamará a esta función (pasando el elemento
como argumento a la función), y la función puede regresar truesi se encuentra una coincidencia, o
de falselo contrario.
Aquí hay un ejemplo en el que usamos std::find_ifpara verificar si algún elemento contiene la subcadena
"nuez":
#include <algorithm>
#include <array>
#include <iostream>
#include <string_view>
int main()
{
std::array<std::string_view, 4> arr{ "apple", "banana", "walnut", "lemon" };
// Scan our array to see if any elements contain the "nut" substring
auto found{ std::find_if(arr.begin(), arr.end(), containsNut) };
if (found == arr.end())
{
std::cout << "No nuts\n";
}
else
{
std::cout << "Found " << *found << '\n';
}
return 0;
}
COPIAR
Producción
Nuez encontrada
Si tuviera que escribir el ejemplo anterior a mano, necesitaría al menos tres bucles (uno para recorrer la
matriz y dos para que coincida con la subcadena). ¡Las funciones estándar de la biblioteca nos permiten
hacer lo mismo en solo unas pocas líneas de código!
#include <algorithm>
#include <array>
#include <iostream>
#include <string_view>
int main()
{
std::array<std::string_view, 5> arr{ "apple", "banana", "walnut", "lemon", "peanut" };
return 0;
}
COPIAR
Producción
Contado 2 tuerca(s)
#include <algorithm>
#include <array>
#include <iostream>
int main()
{
std::array arr{ 13, 90, 99, 5, 40, 80 };
return 0;
}
COPIAR
Producción
99 90 80 40 13 5
Una vez más, en lugar de escribir nuestras propias funciones de bucle personalizadas, ¡podemos ordenar
nuestra matriz como queramos en solo unas pocas líneas de código!
Nuestra greaterfunción necesita 2 argumentos, pero no le estamos pasando ninguno, entonces, ¿de dónde
vienen? Cuando usamos una función sin paréntesis (), es solo un puntero de función, no una
llamada. Puede que recuerdes esto de cuando intentamos imprimir una función sin paréntesis e
imprimimos std::cout"1". std::sortusa este puntero y llama a la greaterfunción real con 2 elementos
cualesquiera de la matriz. No sabemos greatercon qué elementos se llamará, porque no está definido qué
algoritmo de clasificación std::sortse está usando debajo del capó. Hablaremos más sobre los punteros
de función en un capítulo posterior.
Consejo
Debido a que la clasificación en orden descendente es tan común, C++ std::greatertambién proporciona
un tipo personalizado (llamado ) para eso (que es parte del encabezado funcional ). En el ejemplo anterior,
podemos reemplazar:
COPIAR
con:
COPIAR
Tenga en cuenta que std::greater{}necesita las llaves porque no es una función invocable. Es un tipo, y
para usarlo, necesitamos instanciar un objeto de ese tipo. Las llaves crean una instancia de un objeto
anónimo de ese tipo (que luego se pasa como argumento a std::sort).
#include <iostream>
#include <iterator>
#include <utility>
std::swap(*startElement, *smallestElement);
}
}
int main()
{
int array[]{ 2, 1, 9, 4, 5 };
sort(std::begin(array), std::end(array));
return 0;
}
COPIAR
Hasta ahora, esto no es nada nuevo y sortsiempre ordena los elementos de menor a mayor. Para agregar
una función de comparación, tenemos que usar un nuevo tipo, std::function<bool(int, int)>, para
almacenar una función que toma 2 parámetros int y devuelve un bool. Trata este tipo como magia por
ahora, lo explicaremos en el capítulo 12 .
COPIAR
Ahora podemos pasar una función de comparación como greatera sort, pero ¿cómo se sortusa? Todo lo
que tenemos que hacer es reemplazar la línea
COPIAR
con
if (compare(*currentElement, *smallestElement))
COPIAR
Ahora la persona que llama sortpuede elegir cómo comparar dos elementos.
std::swap(*startElement, *smallestElement);
}
}
int main()
{
int array[]{ 2, 1, 9, 4, 5 };
return 0;
}
COPIAR
#include <algorithm>
#include <array>
#include <iostream>
void doubleNumber(int& i)
{
i *= 2;
}
int main()
{
std::array arr{ 1, 2, 3, 4 };
return 0;
}
COPIAR
Producción
2468
Esto a menudo parece el algoritmo más innecesario para los nuevos desarrolladores, porque el código
equivalente con un ciclo for basado en rango es más corto y más fácil. Pero hay beneficios
para std::for_each. Comparemos std::for_eachcon un bucle for basado en rango.
std::ranges::for_each(arr, doubleNumber); // Since C++20, we don't have to use begin() and end().
// std::for_each(arr.begin(), arr.end(), doubleNumber); // Before C++20
COPIAR
Con std::for_each, nuestras intenciones son claras. Llame doubleNumbercon cada elemento de arr. En el
ciclo for basado en rango, tenemos que agregar una nueva variable, i. Esto conduce a varios errores que
un programador podría cometer cuando está cansado o no presta atención. Por un lado, podría haber una
conversión implícita si no usamos auto. Podríamos olvidar el ampersand, y doubleNumberno afectaría la
matriz. Accidentalmente podríamos pasar una variable que no sea ia doubleNumber. Estos errores no
pueden ocurrir con std::for_each.
Además, std::for_eachpuede omitir elementos al principio o al final de un contenedor, por ejemplo, para
omitir el primer elemento de arr, std::nextse puede usar para avanzar al siguiente elemento.
COPIAR
Esto no es posible con un ciclo for basado en rango.
Al igual que muchos algoritmos, std::for_eachse puede paralelizar para lograr un procesamiento más
rápido, lo que lo hace más adecuado para grandes proyectos y big data que un bucle for basado en rango.
Orden de ejecución
Tenga en cuenta que la mayoría de los algoritmos en la biblioteca de algoritmos no garantizan un orden
particular de ejecución. Para tales algoritmos, tenga cuidado de asegurarse de que ninguna función que
pase no asuma un orden particular, ya que el orden de invocación puede no ser el mismo en todos los
compiladores.
Rangos en C++20
La biblioteca de algoritmos tiene un montón de funciones útiles que pueden hacer que su código sea más
simple y robusto. Solo cubrimos un pequeño subconjunto en esta lección, pero debido a que la mayoría de
estas funciones funcionan de manera muy similar, una vez que sepa cómo funcionan algunas, podrá
utilizar la mayoría de ellas.