Punteros y memoria

Punteros a función y callbacks en C y C++

En esta lección vas a pasar una función como parámetro a otra función, con punteros a función en C y con lambdas en C++.

Introducción

Un callback consiste en pasar una función a otra función, que la llamará cuando la necesite. Así, un algoritmo genérico puede ejecutar el comportamiento que elige quien lo llama sin conocer los detalles de su implementación. Por ejemplo, la misma función apply puede elevar al cuadrado, duplicar o aplicar cualquier otra transformación.

Puntos importantes

  • Un puntero solo debe apuntar a un objeto que todavía existe, del tipo correcto, o valer null.
  • Cada zona de memoria reservada debe liberarse exactamente una vez.
  • Deja claro qué función es dueña de la memoria (ownership) y qué datos solo se leen (const).

Ejemplos de código C y C++

C
Ejecutar →
main.c
#include <stdio.h>

int square(int value) { return value * value; }
int apply(int value, int (*operation)(int)) { return operation(value); }

int main(void) {
    printf("%d\n", apply(6, square));
    return 0;
}
Resultado de la ejecución
36
C++
Ejecutar →
main.cpp
#include <functional>
#include <iostream>

int apply(int value, const std::function<int(int)>& operation) {
    return operation(value);
}

int main() {
    int factor = 6;
    std::cout << apply(factor, [](int value) { return value * value; }) << '\n';
}
Resultado de la ejecución
36

Comparación entre C y C++

En C, el parámetro int (*operation)(int) es un puntero a función que acepta una función que recibe un int y devuelve un int, así que apply(6, square) devuelve 36. En C++, las lambdas y std::function pueden contener una variedad más amplia de objetos invocables (callables). En código donde el rendimiento importa, una plantilla (template) suele ser mejor opción que std::function.

C

La propiedad y la liberación de la memoria dependen por completo del programador.

C++

Los contenedores y RAII liberan automáticamente los recursos cuando el objeto llega al final de su vida.

Ejercicios de práctica

Ejecuta las dos versiones y después modifica el código para ver la diferencia de seguridad que aporta cada lenguaje.

  • Prueba con punteros nulos y con fallos al reservar memoria.
  • Ejecuta el programa con AddressSanitizer y UndefinedBehaviorSanitizer para detectar errores de memoria.
  • Deja claro qué puntero es dueño de la memoria y cuál solo sirve para leer.

Practica con un reto

Usa lo que cubre esta lección para resolver un problema real. Cada reto se ejecuta en el navegador, con pruebas al instante y una revisión de IA.

Todos los retos