Ponteiros Inteligentes em C++
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 15 de 104.
Ponteiros inteligentes são classes wrapper que gerenciam automaticamente a memória do heap para você. Eles eliminam a necessidade de chamadas manuais a delete, liberando a memória quando o ponteiro sai do escopo.
Inclua o cabeçalho <memory> para usar ponteiros inteligentes.
unique_ptr - propriedade exclusiva. Apenas um ponteiro pode ser proprietário do recurso por vez.
#include <memory>
std::unique_ptr<Player> player = std::make_unique<Player>("Hero");
player->attack(); // Use como um ponteiro comum
// Não pode copiar, mas pode transferir a posse
std::unique_ptr<Player> player2 = std::move(player);
// player agora é nullptrshared_ptr - propriedade compartilhada. Vários ponteiros podem ser proprietários do mesmo recurso. A memória é liberada quando o último proprietário é destruído.
std::shared_ptr<Player> p1 = std::make_shared<Player>("Hero");
std::shared_ptr<Player> p2 = p1; // Ambos possuem o recurso
std::cout << p1.use_count(); // Imprime 2weak_ptr - observador não proprietário de um shared_ptr. Útil para quebrar referências circulares.
std::shared_ptr<Player> shared = std::make_shared<Player>("Hero");
std::weak_ptr<Player> weak = shared;
if (auto locked = weak.lock()) { // Converter para shared_ptr
locked->attack();
}Use unique_ptr por padrão para propriedade única. Use shared_ptr quando múltiplos objetos precisarem compartilhar um recurso. Use weak_ptr para observar sem estender o tempo de vida.
Prefira make_unique e make_shared em vez do new bruto.
Desafio
FácilVamos criar um sistema de compartilhamento de documentos que demonstra os diferentes modelos de propriedade dos ponteiros inteligentes. Você verá como unique_ptr impõe a propriedade exclusiva, como shared_ptr permite vários proprietários e como weak_ptr pode observar sem afetar o tempo de vida.
Você criará dois arquivos para organizar seu código:
Document.h: Defina uma classeDocumentque represente um documento compartilhável. Ela deve ter:- Um atributo privado
title(string) - Um construtor que receba um título e imprima
"Document created: <title>" - Um destrutor que imprima
"Document deleted: <title>" - Um método
getTitle()que retorne o título
- Um atributo privado
main.cpp: Demonstre os três tipos de ponteiros inteligentes lendo um título de documento da entrada e, em seguida:- Crie um
unique_ptrpara um Document com o título informado - Imprima
"Unique owner: <title>" - Transfira a propriedade para outro
unique_ptrusandostd::move - Imprima
"Ownership transferred" - Crie um
shared_ptrpara um novo Document com o título"SharedDoc" - Crie um segundo
shared_ptrapontando para o mesmo documento - Imprima
"Shared owners: <count>"usandouse_count() - Crie um
weak_ptra partir de um dos ponteiros compartilhados - Use
lock()para acessar o documento por meio do ponteiro fraco e imprima"Weak access: <title>"
- Crie um
Lembre-se de incluir <memory> para usar ponteiros inteligentes. Use std::make_unique e std::make_shared para criar seus ponteiros inteligentes. As mensagens do destrutor ajudarão você a ver quando cada documento é limpo automaticamente no final do programa.
Inclua seu arquivo de cabeçalho em main.cpp usando #include "Document.h".
Experimente você mesmo
#include <iostream>
#include <memory>
#include <string>
#include "Document.h"
using namespace std;
int main() {
string inputTitle;
cin >> inputTitle;
// TODO: Criar um unique_ptr para um Document com inputTitle
// usando std::make_unique
// TODO: Imprimir "Unique owner: <title>"
// TODO: Transferir a posse para outro unique_ptr usando std::move
// TODO: Imprimir "Ownership transferred"
// TODO: Criar um shared_ptr para um novo Document com o título "SharedDoc"
// usando std::make_shared
// TODO: Criar um segundo shared_ptr apontando para o mesmo documento
// TODO: Imprimir "Shared owners: <count>" usando use_count()
// TODO: Criar um weak_ptr a partir de um dos shared pointers
// TODO: Usar lock() para acessar o documento através do weak_ptr
// e imprimir "Weak access: <title>"
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos externosBuild e compilação em C++Arquivos de cabeçalho e arquivos-fonteNamespaces e escopoIntrodução à POO em C++Classes vs. objetosO ponteiro 'this'Métodos (funções membro)Atributos (membros de dados)Noções básicas de construtores e destruidoresRevisão - calculadora simples4Propriedades de Classe
Membros de Instância vs. EstáticosGetters e SettersFunções Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRevisão - Gerenciador de Contas Bancárias7Herança
Herança básicaNíveis de acesso da herançaOrdem de chamada de construtor e destrutorSobrescrita de métodosFunções virtuais e VTableHerança múltiplaHerança virtualRevisão - Hierarquia de funcionários10Visão geral da STL
Visão geral e filosofia da STLContêineres da STLIteradoresAlgoritmos da STLFunctors e expressões lambdaRecapitulação - Frequência de palavras13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonFactory e Abstract FactoryPadrão BuilderPadrão ObserverPadrão Strategy2Gerenciamento de Memória
Memória Stack vs. HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Ponteiros Inteligentes em C++RAII em C++Revisão - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de acesso em C++Especificadores de acesso em profundidadeOcultação de informaçõesStruct vs ClasseClasses aninhadas e internasRecapitulação - Sistema de registros de alunos8Polimorfismo
Polimorfismo em compilação vs. execuçãoSobrecarga de funçõesFunções virtuais revisadasFunções virtuais purasClasses abstratasDesign de interfaces em C++Conversão dinâmica e RTTIRecapitulação — Calculadora de formas11Conceitos Avançados de OOP
Composição vs. HerançaMixins via CRTPIdioma PimplApagamento de TiposClasses Enum e Tipagem ForteTratamento de Exceções em OOPHierarquias de Exceções Personalizadas14Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositeRAII como Padrão3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentoListas de Inicialização do ConstrutorConstrutores DelegantesAprofundamento em DestrutoresRegra dos Três / Cinco / ZeroRevisão - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de FluxoSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçõesTemplates de ClassesEspecialização de TemplatesTemplates VariádicosNoções Básicas de SFINAE e Traits de TiposRecapitulação - Contêiner GenéricoPratique por conta própria: Compilador de C++ online