Sobes.tech
Middle

O que você sabe sobre ponteiros inteligentes em C++?

sobes.tech IA

Resposta da IA

Os ponteiros inteligentes são wrappers RAII sobre ponteiros normais (crus) em C++, que fornecem controlo automático do tempo de vida da memória alocada, prevenindo fugas.

Os principais tipos de ponteiros inteligentes na biblioteca padrão de C++:

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

std::unique_ptr

  • Possui o recurso de forma exclusiva.
  • Não pode ser copiado, mas pode ser movido.
  • Usado para a posse única do recurso.
  • Os custos adicionais são mínimos, equivalentes a um ponteiro cru.
// exemplo 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; // Erro de compilação: unique_ptr não é copiado
    std::unique_ptr<int> ptr3 = std::move(ptr); // Movimento de posse
    std::cout << *ptr3 << std::endl; // 10
    // std::cout << *ptr << std::endl; // Comportamento indefinido: ptr agora está vazio
    return 0;
}

std::shared_ptr

  • Permite que múltiplos ponteiros partilhem a posse de um recurso.
  • Usa um contador de referências. A memória é libertada quando o contador chega a zero.
  • Pode ser copiado. Cada cópia aumenta o contador de referências.
  • Tem custos adicionais mais altos em comparação com unique_ptr devido à gestão do contador.
// exemplo 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; // Cópia, aumenta use_count
    std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 2)
    std::shared_ptr<int> ptr3 = ptr1; // Outra cópia
    std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 3)
    return 0;
}

std::weak_ptr

  • Não possui o recurso e não aumenta o contador de referências.
  • Usado para resolver o problema de referências cíclicas entre shared_ptr.
  • Permite aceder ao recurso apontado por shared_ptr, mas não impede a sua eliminação.
  • Para aceder ao recurso, é necessário converter weak_ptr em shared_ptr usando o método lock().
// exemplo 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 << "Recurso foi libertado." << std::endl;
    }

    shared_ptr_int.reset(); // Recurso libertado

    if (auto locked_ptr = weak_ptr_int.lock()) {
        std::cout << *locked_ptr << std::endl;
    } else {
        std::cout << "Recurso foi libertado." << std::endl; // Recurso foi libertado.
    }
    return 0;
}

O uso de ponteiros inteligentes é uma boa prática na programação moderna em C++, pois reduz significativamente a probabilidade de erros na gestão de memória.