Sobes.tech
Middle

Cosa sai sugli smart pointer in C++?

sobes.tech AI

Risposta dell'AI

I puntatori intelligenti sono wrapper RAII sui puntatori normali (crudi) in C++, che forniscono un controllo automatico sulla durata della memoria allocata, prevenendo perdite.

I principali tipi di puntatori intelligenti nella libreria standard di C++:

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

std::unique_ptr

  • Possiede la risorsa in modo esclusivo.
  • Non può essere copiato, ma può essere spostato.
  • Viene usato per il possesso unico della risorsa.
  • I costi aggiuntivi sono minimi, equivalenti a un puntatore crudo.
// esempio di 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; // Errore di compilazione: unique_ptr non può essere copiato
    std::unique_ptr<int> ptr3 = std::move(ptr); // Trasferimento di possesso
    std::cout << *ptr3 << std::endl; // 10
    // std::cout << *ptr << std::endl; // Comportamento indefinito: ptr ora è vuoto
    return 0;
}

std::shared_ptr

  • Permette a più puntatori di condividere la proprietà di una risorsa.
  • Usa un contatore di riferimenti. La memoria viene liberata quando il contatore raggiunge zero.
  • Può essere copiato. Ogni copia aumenta il contatore di riferimenti.
  • Ha costi più elevati rispetto a unique_ptr a causa della gestione del contatore.
// esempio di 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, aumenta use_count
    std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 2)
    std::shared_ptr<int> ptr3 = ptr1; // Un'altra copia
    std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 3)
    return 0;
}

std::weak_ptr

  • Non possiede la risorsa e non aumenta il contatore di riferimenti.
  • Viene usato per risolvere il problema di riferimenti ciclici tra shared_ptr.
  • Permette di accedere alla risorsa puntata da shared_ptr, ma non ne impedisce la rimozione.
  • Per accedere alla risorsa, è necessario convertire weak_ptr in shared_ptr usando il metodo lock().
// esempio di 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 << "Risorsa è stata rilasciata." << std::endl;
    }

    shared_ptr_int.reset(); // Risorsa viene rilasciata

    if (auto locked_ptr = weak_ptr_int.lock()) {
        std::cout << *locked_ptr << std::endl;
    } else {
        std::cout << "Risorsa è stata rilasciata." << std::endl; // Risorsa è stata rilasciata.
    }
    return 0;
}

L'uso di puntatori intelligenti è una buona pratica nella programmazione moderna in C++, poiché riduce significativamente la probabilità di errori nella gestione della memoria.