Sobes.tech
Middle

¿Qué sabes sobre los punteros inteligentes en C++?

sobes.tech AI

Respuesta de la IA

Los punteros inteligentes son envoltorios RAII sobre punteros normales (crudos) en C++, que proporcionan un control automático del tiempo de vida de la memoria asignada, previniendo fugas.

Los tipos principales de punteros inteligentes en la biblioteca estándar de C++:

  • std::unique_ptr
  • std::shared_ptr
  • std::weak_ptr

std::unique_ptr

  • Posee el recurso de manera exclusiva.
  • No puede ser copiado, pero puede ser movido.
  • Se usa para la posesión única del recurso.
  • Los costos adicionales son mínimos, equivalentes a un puntero crudo.
// ejemplo de unique_ptr
#include <memory>
#include <iostream>

int main() {
    std::unique_ptr<int> ptr = std::make_unique<int>(10);
    std::cout << *ptr << std::endl; // 10
    // std::unique_ptr<int> ptr2 = ptr; // Error de compilación: unique_ptr no se copia
    std::unique_ptr<int> ptr3 = std::move(ptr); // Movimiento de posesión
    std::cout << *ptr3 << std::endl; // 10
    // std::cout << *ptr << std::endl; // Comportamiento indefinido: ptr ahora está vacío
    return 0;
}

std::shared_ptr

  • Permite que múltiples punteros compartan la posesión de un recurso.
  • Usa un contador de referencias. La memoria se libera cuando el contador llega a cero.
  • Puede ser copiado. Cada copia incrementa el contador de referencias.
  • Tiene costos adicionales más altos en comparación con unique_ptr debido a la gestión del contador.
// ejemplo de shared_ptr
#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>(20);
    std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 1)
    std::shared_ptr<int> ptr2 = ptr1; // Copia, incrementa use_count
    std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 2)
    std::shared_ptr<int> ptr3 = ptr1; // Otra copia
    std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 3)
    return 0;
}

std::weak_ptr

  • No posee el recurso y no incrementa el contador de referencias.
  • Se usa para resolver el problema de referencias cíclicas entre shared_ptr.
  • Permite acceder al recurso apuntado por shared_ptr, pero no evita su eliminación.
  • Para acceder al recurso, es necesario convertir weak_ptr en shared_ptr usando el método lock().
// ejemplo de weak_ptr
#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> shared_ptr_int = std::make_shared<int>(30);
    std::weak_ptr<int> weak_ptr_int = shared_ptr_int;

    if (auto locked_ptr = weak_ptr_int.lock()) {
        std::cout << *locked_ptr << std::endl; // 30
    } else {
        std::cout << "El recurso ha sido liberado." << std::endl;
    }

    shared_ptr_int.reset(); // Se libera el recurso

    if (auto locked_ptr = weak_ptr_int.lock()) {
        std::cout << *locked_ptr << std::endl;
    } else {
        std::cout << "El recurso ha sido liberado." << std::endl; // El recurso ha sido liberado.
    }
    return 0;
}

El uso de punteros inteligentes es una buena práctica en el C++ moderno, ya que reduce significativamente la probabilidad de errores en la gestión de memoria.