Sobes.tech
Senior

Como implementar um ponteiro inteligente para um ou vários objetos?

sobes.tech IA

Resposta da IA

Para um único objeto: unique_ptr ou shared_ptr. Para múltiplos objetos: shared_ptr (propriedade compartilhada) ou weak_ptr (observação sem participação na gestão do ciclo de vida).

#include <memory>
#include <vector>

// Exemplo de classe de objeto
class MyObject {
public:
    MyObject() { /* Construtor */ }
    ~MyObject() { /* Destruidor */ }
};

// Para um único objeto: unique_ptr (propriedade exclusiva)
void single_unique_ptr() {
    std::unique_ptr<MyObject> ptr = std::make_unique<MyObject>();
    // O objeto será eliminado automaticamente ao sair do escopo
}

// Para um único objeto: shared_ptr (propriedade compartilhada)
void single_shared_ptr() {
    std::shared_ptr<MyObject> ptr = std::make_shared<MyObject>();
    // A contagem de proprietários aumenta
    std::shared_ptr<MyObject> another_ptr = ptr;
    // O objeto será eliminado quando o último shared_ptr deixar de referenciá-lo
}

// Para múltiplos objetos: vetor com shared_ptr
void multiple_shared_ptr() {
    std::vector<std::shared_ptr<MyObject>> objects;
    objects.push_back(std::make_shared<MyObject>());
    objects.push_back(std::make_shared<MyObject>());
    // Cada objeto é gerido pelo seu próprio shared_ptr no vetor
    // Os objetos serão eliminados após a eliminação dos shared_ptr correspondentes
}

// Para múltiplos objetos: vetor com unique_ptr
void multiple_unique_ptr() {
    std::vector<std::unique_ptr<MyObject>> objects;
    objects.push_back(std::make_unique<MyObject>());
    objects.push_back(std::make_unique<MyObject>());
    // Neste caso, o vetor possui os ponteiros únicos
    // Os objetos serão eliminados ao sair do escopo do vetor

    // Nota: unique_ptr não pode ser copiado, apenas movido (move)
    std::unique_ptr<MyObject> moved_ptr = std::move(objects[0]);
}

Comparação entre unique_ptr e shared_ptr:

Característica std::unique_ptr std::shared_ptr
Propriedade Única Compartilhada (contador de referências)
Cópia Não (apenas movimento) Sim
Desempenho Um pouco mais rápido (sem custos de contador de referências) Um pouco mais lento (contador de referências)
Referências cíclicas Não protege Pode causar vazamentos de memória (requer weak_ptr)

std::weak_ptr é usado para observar um objeto gerenciado por shared_ptr sem aumentar o contador de referências, evitando problemas de referências cíclicas.

#include <memory>

class Node {
public:
    std::shared_ptr<Node> next;
    std::weak_ptr<Node> previous; // Uso de weak_ptr para evitar referência cíclica

    Node() = default;
    ~Node() { /* Destructeur */ }
};

void weak_ptr_example() {
    std::shared_ptr<Node> node1 = std::make_shared<Node>();
    std::shared_ptr<Node> node2 = std::make_shared<Node>();

    node1->next = node2;
    node2->previous = node1; // Usamos weak_ptr

    // Pode obter um shared_ptr de weak_ptr para acessar o objeto
    if (std::shared_ptr<Node> locked_node = node2->previous.lock()) {
        // Se o objeto ainda estiver vivo
        // ... trabalhar com locked_node
    } else {
        // O objeto já foi eliminado
    }
}