Logo Passei Direto
Buscar
Material
páginas com resultados encontrados.
páginas com resultados encontrados.

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Prévia do material em texto

C/C++
C/C++
C++ Smart Pointers
Maria Luiza Sperancin Mancebo
Palavras-chaves: ponteiros brutos, ponteiros inteligentes, memória, unique_ptr, shared_ptr
1. Diferenças (2)
Um ponteiro bruto em C++ é uma variável que armazena o endereço de memória de outro
valor ou função. Ele tem três propósitos principais:
● Alocar novos objetos no heap,
● Passar funções para outras funções,
● Iterar sobre os elementos em matrizes ou outras estruturas de dados.
Com um ponteiro, você pode fazer referência a outros espaços de memória, o que pode ser
extremamente útil. No entanto, os ponteiros brutos podem ser difíceis de gerenciar, pois você precisa
se lembrar de desalocar qualquer memória que você alocou para evitar vazamentos de memória.
int* ponteiro_bruto = new int(10); // cria um ponteiro bruto para um int
delete ponteiro_bruto; // desaloca a memória
Figura 1
Na figura 1, é criado um ponteiro bruto para um int, e logo em seguida ele é desalocado. Isso é
feito já que como citado anteriormente, é necessário desalocar sua memória para evitar vazamentos.
Os ponteiros inteligentes são objetos que se parecem e se sentem como ponteiros, mas são
mais seguros porque gerenciam a memória automaticamente. Eles foram introduzidos para resolver
problemas comuns com ponteiros brutos, como vazamentos de memória e ponteiros pendurados.
Existem três tipos principais de ponteiros inteligentes em C++: unique_ptr, shared_ptr e weak_ptr.
std::unique_ptr<int> ponteiro_inteligente(new int(10)); // cria um ponteiro
// inteligente para um int
// a memória é automaticamente desalocada quando ponteiro_inteligente sai de
escopo
Figura 2
Na figura 2, por sua vez, é criado um ponteiro inteligente e não é feita sua desalocação, já que
eles gerenciam automaticamente a memória, e essa é a principal diferença entre eles e os ponteiros
brutos. Quando um ponteiro inteligente sai de escopo, ele automaticamente desaloca a memória para a
qual aponta. Isso ajuda a prevenir vazamentos de memória, que são um problema comum ao usar
ponteiros brutos.
Por outro lado, os ponteiros brutos são mais leves e têm menos sobrecarga do que os ponteiros
inteligentes. Eles também permitem um controle mais preciso sobre a memória, o que pode ser
necessário em alguns casos.
2. Perigos (4)
Os principais perigos que existem na utilização de ponteiros brutos são:
a) Vazamento de Memória
Um dos perigos mais comuns ao usar ponteiros brutos é o vazamento de memória. Isso ocorre
quando a memória é alocada, mas não é desalocada corretamente. Se um ponteiro bruto que aponta
para uma alocação de memória é sobrescrito ou sai de escopo sem primeiro desalocar a memória, essa
memória não pode ser recuperada até que o programa termine. Isso pode levar a um uso significativo e
desnecessário de memória, que se torna especialmente problemático em programas de longa duração.
Além disso, o vazamento de memória em C++ pode ocorrer devido a exceções não capturadas.
Quando uma exceção é lançada, mas não é capturada em nenhum bloco de captura, o programa
termina abruptamente. Se a exceção foi lançada durante a execução de um bloco de código que alocou
memória dinamicamente, mas ainda não a desalocou, essa memória é perdida.
b) Ponteiros Pendentes
Outro perigo são os ponteiros pendentes. Isso ocorre quando você tem um ponteiro que aponta
para um objeto que foi desalocado. Tentar acessar o objeto através do ponteiro pendurado pode levar a
comportamento indefinido, pois a memória anteriormente ocupada pelo objeto pode agora conter
diferentes dados, ou pode ter sido liberada de volta para o sistema.
Além disso, os ponteiros pendentes podem ser particularmente perigosos porque o
comportamento do programa pode variar. Como a memória que o ponteiro pendente aponta pode ser
realocada, o ponteiro pode apontar para dados que parecem válidos, mas na verdade são
completamente diferentes do objeto original. Isso pode levar a erros sutis e difíceis de rastrear.
Os ponteiros pendentes também podem levar a violações de segurança. Se um invasor puder
manipular o programa para escrever dados na memória apontada por um ponteiro pendente, ele poderá
ser capaz de executar código arbitrário ou acessar informações sensíveis.
c) Acesso Fora dos Limites
Os ponteiros brutos não têm informações sobre o tamanho dos dados para os quais estão
apontando. Isso pode levar a erros de acesso fora dos limites, onde o programa tenta acessar a
memória além do final do objeto alocado. Isso pode resultar em comportamento indefinido.
d) Incompatibilidade de Tipo
Os ponteiros brutos em C++ são fracamente tipados. Isso significa que um ponteiro de um tipo
pode ser convertido em um ponteiro de outro tipo sem qualquer verificação de tipo em tempo de
compilação. Isso pode levar a erros se o ponteiro for desreferenciado e o dado for interpretado como o
tipo errado.
3. Unique_ptr (5)
O unique_ptr é um tipo de ponteiro inteligente introduzido no C++11 como parte da biblioteca
padrão. Ele foi projetado para gerenciar a propriedade de um objeto único, garantindo que o objeto
seja destruído corretamente quando o unique_ptr sai do escopo.
Algumas características importantes do unique_ptr são:
a) Propriedade Única
A propriedade única é uma característica fundamental do unique_ptr que garante que apenas
um unique_ptr possa possuir um objeto específico a qualquer momento.
Isso é importante por várias razões, como evitar a duplicação de liberação de memória, ou
seja, se dois ponteiros apontarem para o mesmo objeto, poderia haver um risco de que o objeto seja
deletado duas vezes, o que pode levar a comportamentos indefinidos. Com a propriedade única, esse
problema é evitado porque apenas um unique_ptr pode possuir o objeto, garantindo que ele seja
deletado apenas uma vez.
Também, a propriedade única traz uma claridade de propriedade, isso é, tornar claro quem é
responsável por deletar o objeto. Isso pode simplificar o código e torná-lo mais fácil de entender, já
que não há dúvidas sobre quem deve liberar a memória.
Além disso, em um ambiente multi-thread, a propriedade única pode ajudar a evitar condições
de corrida relacionadas à desalocação de memória. Como apenas um unique_ptr pode possuir o objeto,
não há risco de que dois threads tentem deletar o objeto simultaneamente.
b) Gerenciamento Automático de Memória
Quando um unique_ptr sai do escopo, o destrutor é chamado automaticamente e o objeto ao
qual ele aponta é destruído. Isso ajuda a prevenir vazamentos de memória.
c) Transferência de Propriedade
A propriedade de um objeto pode ser transferida de um unique_ptr para outro usando o
método std::move(). Isso é útil quando você precisa passar a propriedade de um objeto para uma
função ou retornar um objeto de uma função.
4. Shared_ptr (6)
O shared_ptr é um tipo de ponteiro inteligente que permite a propriedade compartilhada de
um objeto. Isso significa que vários shared_ptr podem possuir o mesmo objeto e o objeto só será
destruído quando todos os outros que apontam para ele forem destruídos.
Algumas características importantes do shared_ptr são:
a) Gerenciamento de Propriedade Compartilhada:
O shared_ptr permite que vários ponteiros apontem para o mesmo objeto. Isso é útil quando
você precisa compartilhar um objeto entre diferentes partes do seu programa sem se preocupar com
quem deve deletar o objeto.
b) Contagem de Referência:
O shared_ptr mantém uma contagem de referência para rastrear quantos ponteiros estão
apontando para o mesmo objeto. Quando essa contagem cai para zero (ou seja, quando não há mais
shared_ptr apontando para o objeto), o objeto é automaticamente destruído.
c) Gerenciamento Automático de Memória:
Assim como unique_ptr, quando um shared_ptr é destruído (por exemplo, quando sai do
escopo), ele automaticamente destrói o objeto ao qual aponta se a contagem de referência for zero.
5. Desempenho (10)
Embora os ponteiros inteligentes possam ajudar a prevenir muitos bugs comuns de
gerenciamento de memória, eles vêm com suas próprias considerações de desempenho que devem serlevadas em conta. É importante entender essas trocas ao decidir usar ponteiros inteligentes em seu
código. Aqui estão algumas considerações de desempenho ao usar esses ponteiros:
a) Sobrecarga de Contagem de Referência
Ponteiros inteligentes como shared_ptr mantém uma contagem de referência para gerenciar a
vida útil do objeto apontado. Cada vez que um shared_ptr é copiado, a contagem de referência é
incrementada e cada vez que é destruído, a contagem de referência é decrementada. Se a contagem de
referência chega a zero, o objeto apontado é destruído. Esta contagem de referência adiciona uma
sobrecarga ao desempenho, especialmente em operações de cópia.
b) Contenção de Bloqueio
A contagem de referência em shared_ptr é thread-safe, o que significa que pode ser acessada
por vários threads simultaneamente sem causar condições de corrida. No entanto, isso é alcançado
através do uso de operações atômicas, que podem causar contenção de bloqueio se muitos threads
estiverem tentando acessar o mesmo shared_ptr simultaneamente. Isso pode levar a uma degradação
do desempenho em programas multithreaded.
c) Sobrecarga de Memória
Ponteiros inteligentes usam mais memória do que ponteiros brutos. Por exemplo, um
shared_ptr precisa armazenar o ponteiro para o objeto, a contagem de referência e, possivelmente, um
deleter personalizado. Isso pode ser significativo em programas que usam uma grande quantidade de
ponteiros. No entanto, esse overhead é justificado pela segurança e gerenciamento automático de
memória que os ponteiros inteligentes oferecem.
Bibliografia
MICROSOFT. Ponteiros brutos (C++). Disponível em:
<https://learn.microsoft.com/pt-br/cpp/cpp/raw-pointers?view=msvc-170>. Acesso em: 21 mar. 2024.
MICROSOFT. Ponteiros inteligentes (C++ moderno). Disponível em:
<https://learn.microsoft.com/pt-br/cpp/cpp/smart-pointers-modern-cpp?view=msvc-170>. Acesso em:
22 mar. 2024.
MICROSOFT. Classe shared_ptr. Disponível em:
<https://learn.microsoft.com/pt-br/cpp/standard-library/shared-ptr-class?view=msvc-170>. Acesso em:
23 mar. 2024.
MICROSOFT. Classe unique_ptr. Disponível em:
<https://learn.microsoft.com/pt-br/cpp/standard-library/unique-ptr-class?view=msvc-170>. Acesso
em: 22 mar. 2024.
MEDIUM. O que é memory leak e como evitar. Disponível em
<https://xfgusta.medium.com/o-que-%C3%A9-memory-leak-e-como-evitar-af7941c334f6>. Acesso
em: 22 mar. 2024.
BABATI, Bence; PATAKI, Norbert. Comprehensive Performance Analysis of C++ Smart Pointers.
Faculty of Informatics, Eötvös Loránd University, 2017. Disponível em:
<https://real.mtak.hu/66602/1/606.2017.12.3.14.pdf>. Acesso em: 25 mar. 2024.
https://learn.microsoft.com/pt-br/cpp/cpp/raw-pointers?view=msvc-170
https://learn.microsoft.com/pt-br/cpp/cpp/smart-pointers-modern-cpp?view=msvc-170
https://learn.microsoft.com/pt-br/cpp/standard-library/shared-ptr-class?view=msvc-170
https://learn.microsoft.com/pt-br/cpp/standard-library/unique-ptr-class?view=msvc-170
https://xfgusta.medium.com/o-que-%C3%A9-memory-leak-e-como-evitar-af7941c334f6
https://real.mtak.hu/66602/1/606.2017.12.3.14.pdf

Mais conteúdos dessa disciplina