<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Memory Management on kenji.blog</title><link>http://kenji.blog/pt/tags/memory-management/</link><description>Recent content in Memory Management on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>pt</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 07:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/pt/tags/memory-management/index.xml" rel="self" type="application/rss+xml"/><item><title>Técnicas de uso de smart pointers (std::unique_ptr / shared_ptr) para evitar vazamentos de memória</title><link>http://kenji.blog/pt/p/cpp-smart-pointers-guide-unique-shared-ptr/</link><pubDate>Sat, 12 Sep 2026 07:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/cpp-smart-pointers-guide-unique-shared-ptr/</guid><description>&lt;img src="http://kenji.blog/p/cpp-smart-pointers-guide-unique-shared-ptr/img/eyecatch.jpg" alt="Featured image of post Técnicas de uso de smart pointers (std::unique_ptr / shared_ptr) para evitar vazamentos de memória" />&lt;p>O gerenciamento de memória em C++ tem sido, por muitos anos, um dos maiores desafios para os desenvolvedores. O estilo tradicional de gerenciamento de memória, que depende de &lt;code>new&lt;/code> e &lt;code>delete&lt;/code> manuais, tornou-se um terreno fértil para a criação de bugs graves, como vazamentos de memória, ponteiros pendentes (dangling pointers) e dupla liberação. No entanto, com a chegada do Modern C++ (C++11 em diante), a situação mudou drasticamente. No centro dessa mudança estão os &amp;ldquo;Smart Pointers&amp;rdquo; (Ponteiros Inteligentes).&lt;/p>
&lt;p>Neste artigo, explicaremos de forma extremamente detalhada os mecanismos e técnicas avançadas de uso do &lt;code>std::unique_ptr&lt;/code>, &lt;code>std::shared_ptr&lt;/code> e &lt;code>std::weak_ptr&lt;/code> - ferramentas poderosas para erradicar vazamentos de memória e realizar um gerenciamento de recursos seguro e eficiente. Abordaremos suas implementações internas (blocos de controle e operações atômicas), impacto no desempenho e a formulação da contagem de referências por meio de modelos matemáticos.&lt;/p>
&lt;h2 id="1-introdução-a-era-sombria-do-gerenciamento-de-memória-em-c-e-o-alvorecer-do-modern-c">1. Introdução: A era sombria do gerenciamento de memória em C++ e o alvorecer do Modern C++
&lt;/h2>&lt;p>No desenvolvimento C++ do passado, a memória alocada no heap precisava ser liberada pelo próprio desenvolvedor, sob sua própria responsabilidade.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">legacy_function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="kt">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ... algum processamento ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">some_condition&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Ocorre um vazamento de memória! delete não é chamado
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">delete&lt;/span> &lt;span class="n">ptr&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Em códigos como o acima, o &lt;code>delete&lt;/code> é ignorado e ocorre um vazamento de memória se houver uma exceção ou um retorno antecipado. O paradigma para evitar isso é o &amp;ldquo;RAII (Resource Acquisition Is Initialization)&amp;rdquo;. O RAII é uma técnica que vincula a aquisição de recursos à inicialização do objeto (construtor) e a liberação de recursos à destruição do objeto (destrutor). Os smart pointers são um conjunto de classes da biblioteca padrão que aplicam este idioma RAII ao gerenciamento de memória.&lt;/p>
&lt;h2 id="2-stdunique_ptr-propriedade-exclusiva-com-zero-overhead">2. &lt;code>std::unique_ptr&lt;/code>: Propriedade exclusiva com zero overhead
&lt;/h2>&lt;p>O &lt;code>std::unique_ptr&lt;/code> é um smart pointer que possui &amp;ldquo;Propriedade Exclusiva (Exclusive Ownership)&amp;rdquo; sobre um objeto alocado dinamicamente. Sempre haverá apenas um &lt;code>unique_ptr&lt;/code> que possui um determinado recurso.&lt;/p>
&lt;h3 id="21-princípio-do-zero-overhead">2.1 Princípio do zero overhead
&lt;/h3>&lt;p>A maior vantagem do &lt;code>std::unique_ptr&lt;/code> é o seu desempenho. No seu estado padrão (sem possuir um custom deleter), o tamanho de um &lt;code>std::unique_ptr&lt;/code> é perfeitamente idêntico ao de um ponteiro bruto (Raw Pointer). Ele não possui nenhuma variável membro desnecessária e funções virtuais não são utilizadas. Devido à otimização do compilador, o acesso feito por meio de um &lt;code>std::unique_ptr&lt;/code> é expandido para o mesmo código assembly que o de um ponteiro bruto.&lt;/p>
&lt;h3 id="22-transferência-de-propriedade-e-stdmove">2.2 Transferência de propriedade e &lt;code>std::move&lt;/code>
&lt;/h3>&lt;p>Por possuir propriedade exclusiva, o &lt;code>std::unique_ptr&lt;/code> não pode ser copiado (o construtor de cópia e o operador de atribuição de cópia foram &amp;ldquo;deletados&amp;rdquo; usando &lt;code>delete&lt;/code>). Para transferir a propriedade para outro &lt;code>unique_ptr&lt;/code>, utilizamos a semântica de movimento (Move Semantics) através da função &lt;code>std::move&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Resource&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Resource&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Resource acquired&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">~&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Resource destroyed&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">do_something&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Doing something&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">process_resource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ptr&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">do_something&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Ao sair do escopo, ptr é destruído e Resource também é liberado
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">my_ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_unique&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// process_resource(my_ptr); // Erro: cópia não permitida
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">process_resource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">move&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">my_ptr&lt;/span>&lt;span class="p">));&lt;/span> &lt;span class="c1">// Transferência de propriedade
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">my_ptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;my_ptr is now empty.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>O diagrama Mermaid a seguir mostra o conceito de transferência de propriedade usando &lt;code>std::move&lt;/code>.&lt;/p>
&lt;div class="mermaid">graph LR
subgraph "Antes de std::move"
A["unique_ptr (ptr1)"] -->|"Possui"| B["Memória Heap (Objeto)"]
end
subgraph "Depois de std::move"
C["unique_ptr (ptr1)"] -.->|"Vazio (nullptr)"| D["nullptr"]
E["unique_ptr (ptr2)"] -->|"Possui"| F["Memória Heap (Objeto)"]
end&lt;/div>
&lt;h3 id="23-implementação-de-custom-deleters">2.3 Implementação de custom deleters
&lt;/h3>&lt;p>Ao encapsular APIs legadas em C (por exemplo, &lt;code>FILE*&lt;/code> ou sockets), muitas vezes precisamos chamar uma função diferente de &lt;code>delete&lt;/code> (como &lt;code>fclose&lt;/code>) para liberar a memória. O &lt;code>std::unique_ptr&lt;/code> permite especificar um &amp;ldquo;custom deleter&amp;rdquo; (deletador personalizado) no seu segundo argumento de template.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;cstdio&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Functor para o custom deleter
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">FileDeleter&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">operator&lt;/span>&lt;span class="p">()(&lt;/span>&lt;span class="n">FILE&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">fp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">fp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Closing file.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fclose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fp&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="n">UniqueFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">FILE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">FileDeleter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">UniqueFile&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fopen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;test.txt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;w&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fputs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Hello, Smart Pointers!&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Ao final do escopo, FileDeleter é chamado e fclose é executado
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Usar ponteiros de função ou expressões lambda como custom deleters pode aumentar o tamanho do &lt;code>unique_ptr&lt;/code>. No entanto, ao usar um objeto de função (Functor) sem estado como mostrado acima, o tamanho não aumentará em relação a um ponteiro bruto graças à &lt;strong>EBCO (Empty Base Class Optimization)&lt;/strong> do C++ ou ao &lt;code>[[no_unique_address]]&lt;/code> introduzido no C++20 (o zero overhead é mantido).&lt;/p>
&lt;h2 id="3-stdshared_ptr-propriedade-compartilhada-e-bloco-de-controle">3. &lt;code>std::shared_ptr&lt;/code>: Propriedade compartilhada e bloco de controle
&lt;/h2>&lt;p>O &lt;code>std::shared_ptr&lt;/code> é um smart pointer para compartilhar a propriedade de um mesmo objeto entre múltiplos ponteiros. Quando o último &lt;code>shared_ptr&lt;/code> é destruído, o objeto gerenciado é liberado.&lt;/p>
&lt;h3 id="31-arquitetura-interna-o-bloco-de-controle-control-block">3.1 Arquitetura interna: O Bloco de Controle (Control Block)
&lt;/h3>&lt;p>Diferente do ponteiro para o objeto sendo gerenciado, o &lt;code>std::shared_ptr&lt;/code> aloca e compartilha no heap metadados chamados de &lt;strong>Bloco de Controle (Control Block)&lt;/strong>. O bloco de controle contém as seguintes informações:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Strong Count (Contagem Forte)&lt;/strong>: O número de instâncias de &lt;code>shared_ptr&lt;/code> que possuem o objeto. Quando isso chega a 0, o objeto é destruído.&lt;/li>
&lt;li>&lt;strong>Weak Count (Contagem Fraca)&lt;/strong>: O número de instâncias de &lt;code>weak_ptr&lt;/code> que estão monitorando o objeto. Quando tanto a Strong Count quanto a Weak Count chegam a 0, o próprio bloco de controle é liberado.&lt;/li>
&lt;li>&lt;strong>Custom Deleter e Alocador&lt;/strong> (se especificados).&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
A["std::shared_ptr&lt;T> (sp1)"] -->|"Ponteiro para T"| B["Objeto Gerenciado (T)"]
A -->|"Ponteiro para Bloco de Controle"| C["Bloco de Controle"]
D["std::shared_ptr&lt;T> (sp2)"] -->|"Ponteiro para T"| B
D -->|"Ponteiro para Bloco de Controle"| C
C -->|"Deleta"| B
C -.->|"Contagem Forte: 2"| E["Contagem Forte"]
C -.->|"Contagem Fraca: 0"| F["Contagem Fraca"]
C -.->|"Custom Deleter"| G["Deletador"]&lt;/div>
&lt;p>Por esse motivo, o tamanho do próprio objeto &lt;code>std::shared_ptr&lt;/code> costuma ser o dobro de um ponteiro bruto (um ponteiro para o objeto e outro ponteiro para o bloco de controle).&lt;/p>
&lt;h3 id="32-desempenho-e-operações-atômicas">3.2 Desempenho e operações atômicas
&lt;/h3>&lt;p>As contagens de referência no bloco de controle são implementadas como &lt;strong>Operações Atômicas (Atomic Operations)&lt;/strong> para garantir incrementos e decrementos seguros, mesmo em um ambiente multithread.&lt;/p>
&lt;p>Nas arquiteturas x86/x64, as instruções atômicas como &lt;code>lock xadd&lt;/code> são usadas para incrementar ou decrementar a contagem de referências. Isso tem um overhead de dezenas de ciclos de clock quando comparado à simples adição de inteiros. Portanto, passar um &lt;code>shared_ptr&lt;/code> por valor a uma função acarretará incrementos e decrementos atômicos a cada cópia, degradando o desempenho.&lt;/p>
&lt;p>&lt;strong>Melhor Prática&lt;/strong>: A menos que seja estritamente necessário compartilhar a propriedade, você deve passar o &lt;code>shared_ptr&lt;/code> para uma função como &lt;code>const std::shared_ptr&amp;lt;T&amp;gt;&amp;amp;&lt;/code> (referência const), ou passar como ponteiro/referência bruto.&lt;/p>
&lt;h3 id="33-stdmake_shared-vs-new">3.3 &lt;code>std::make_shared&lt;/code> vs &lt;code>new&lt;/code>
&lt;/h3>&lt;p>Ao gerar um &lt;code>shared_ptr&lt;/code>, você deve usar &lt;code>std::make_shared&lt;/code> sempre que possível. Existem duas razões principais para isso.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Otimização de alocação de memória&lt;/strong>:
Usar &lt;code>new&lt;/code> resulta em duas alocações no heap: uma para o objeto em si e outra para o bloco de controle. Usar &lt;code>std::make_shared&lt;/code> permite alocar de uma só vez um grande bloco de memória no heap que abrange a ambos, melhorando também a eficiência do cache.&lt;/li>
&lt;li>&lt;strong>Segurança contra exceções (Exception Safety)&lt;/strong>:
Nos padrões anteriores ao C++17, a ordem de avaliação dos argumentos da função não era definida, e se uma exceção ocorresse na avaliação de outros argumentos antes que o ponteiro alocado com &lt;code>new&lt;/code> fosse passado para o construtor do &lt;code>shared_ptr&lt;/code>, havia risco de vazamento de memória. O &lt;code>make_shared&lt;/code> evita completamente este problema.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Prática a ser evitada (2 alocações de memória)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span> &lt;span class="n">MyClass&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Prática recomendada (1 alocação de memória)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="4-stdweak_ptr-resolvendo-referências-circulares-e-monitoramento">4. &lt;code>std::weak_ptr&lt;/code>: Resolvendo referências circulares e monitoramento
&lt;/h2>&lt;p>A propriedade compartilhada possui uma fraqueza fatal chamada &amp;ldquo;Referências Circulares (Circular References)&amp;rdquo;. Se o Objeto A e o Objeto B apontarem um para o outro com &lt;code>shared_ptr&lt;/code>, a Strong Count de ambos será mantida em pelo menos 1, e como nunca chegará a 0 até o final do programa, ocorrerá um vazamento de memória.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Referência Circular (Vazamento de Memória)"
A["Objeto A"] -->|"shared_ptr (Forte=1)"| B["Objeto B"]
B -->|"shared_ptr (Forte=1)"| A
end&lt;/div>
&lt;h3 id="41-quebrando-ciclos-com-stdweak_ptr">4.1 Quebrando ciclos com &lt;code>std::weak_ptr&lt;/code>
&lt;/h3>&lt;p>O &lt;code>std::weak_ptr&lt;/code> resolve este problema. O &lt;code>weak_ptr&lt;/code> é gerado a partir de um &lt;code>shared_ptr&lt;/code> e faz referência ao objeto, mas &lt;strong>não incrementa a Strong Count&lt;/strong>. Em vez disso, ele incrementa a Weak Count. Isso permite &amp;ldquo;monitorar&amp;rdquo; o objeto sem ter a propriedade sobre ele.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Quebrando a Referência Circular"
C["Objeto A"] -->|"shared_ptr (Forte=1)"| D["Objeto B"]
D -.->|"weak_ptr (Fraca=1)"| C
end&lt;/div>
&lt;h3 id="42-acesso-seguro-através-do-método-lock">4.2 Acesso seguro através do método &lt;code>lock()&lt;/code>
&lt;/h3>&lt;p>O &lt;code>weak_ptr&lt;/code> não possui operadores (como &lt;code>-&amp;gt;&lt;/code> ou &lt;code>*&lt;/code>) para acessar o objeto de forma direta. Isso ocorre porque existe a possibilidade do objeto de destino já ter sido destruído. Para acessar de forma segura, deve-se chamar o método &lt;code>lock()&lt;/code> e obter temporariamente um &lt;code>shared_ptr&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Node&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">next&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">weak_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">prev&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Usa weak_ptr para evitar referência circular
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Node&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Created &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">~&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Destroyed &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">nodeA&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;A&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">nodeB&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;B&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nodeA&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">next&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeB&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nodeB&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeA&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Obtém o shared_ptr a partir do weak_ptr para o acesso
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">auto&lt;/span> &lt;span class="n">locked_prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeB&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">prev&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lock&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Node B&amp;#39;s prev is &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">locked_prev&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Node B&amp;#39;s prev is already destroyed.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// nodeA e nodeB são adequadamente destruídos
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="5-restrições-da-propriedade-compartilhada-em-ambientes-multithread">5. Restrições da propriedade compartilhada em ambientes multithread
&lt;/h2>&lt;p>A segurança das threads (thread-safety) no &lt;code>shared_ptr&lt;/code> costuma ser bastante incompreendida. &amp;ldquo;A atualização da contagem de referências dentro do bloco de controle é thread-safe&amp;rdquo;, no entanto &amp;ldquo;a leitura e escrita do próprio objeto &lt;code>shared_ptr&lt;/code> não é thread-safe&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Operação Segura&lt;/strong>: Múltiplas threads lendo e escrevendo, &lt;em>cada uma na sua própria&lt;/em> instância do &lt;code>shared_ptr&lt;/code> (mesmo que compartilhem o mesmo bloco de controle).&lt;/li>
&lt;li>&lt;strong>Data race (Perigo)&lt;/strong>: Múltiplas threads lendo e escrevendo simultaneamente sobre a &lt;em>mesma exata&lt;/em> instância do &lt;code>shared_ptr&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Caso precise compartilhar a mesma instância em várias threads, será necessário utilizar &lt;code>std::atomic&amp;lt;std::shared_ptr&amp;lt;T&amp;gt;&amp;gt;&lt;/code> (C++20) ou protegê-la com um mutex (&lt;code>std::mutex&lt;/code>).&lt;/p>
&lt;h2 id="6-formulação-matemática-da-contagem-de-referências">6. Formulação matemática da contagem de referências
&lt;/h2>&lt;p>Expressando as transições de estados do ciclo de vida dentro do bloco de controle de maneira matemática, temos o seguinte.
Seja $S(t)$ a Strong Count no tempo $t$ e $W(t)$ a Weak Count.&lt;/p>
&lt;p>Estado inicial (logo após &lt;code>make_shared&lt;/code>):
&lt;/p>
$$ S(0) = 1, \quad W(0) = 0 $$
&lt;p>Quando ocorre uma cópia (duplicação de &lt;code>shared_ptr&lt;/code>):
&lt;/p>
$$ S(t_{next}) = S(t) + 1 $$
&lt;p>A condição para que o objeto gerenciado (Managed Object) seja destruído:
&lt;/p>
$$ \lim_{t \to t_d} S(t) = 0 $$
&lt;p>A condição para que o próprio bloco de controle (Control Block) seja liberado da memória:
&lt;/p>
$$ S(t) = 0 \quad \land \quad W(t) = 0 $$
&lt;p>
Ou seja,
&lt;/p>
$$ S(t) + W(t) = 0 $$
&lt;p>Como as fórmulas acima sugerem, contanto que um &lt;code>weak_ptr&lt;/code> continue existindo ($W(t) > 0$), o pequeno espaço de memória para o bloco de controle continuará reservado, mesmo que o objeto gerenciado seja destruído. Esse seria o único cenário em que o uso do &lt;code>make_shared&lt;/code> traria desvantagem (uma vez que a memória do objeto gerenciado e a do bloco de controle foram alocadas juntas, se restar alguma referência fraca, o grande espaço de memória destinado ao objeto gerenciado não retornará ao sistema). Contudo, na maior parte do tempo, a vantagem no desempenho do &lt;code>make_shared&lt;/code> supera esse ponto negativo com folga.&lt;/p>
&lt;h2 id="7-conclusão">7. Conclusão
&lt;/h2>&lt;p>O gerenciamento de memória em Modern C++ não está mais na época de fazer a gestão com &lt;code>new&lt;/code>/&lt;code>delete&lt;/code> manualmente.&lt;/p>
&lt;ol>
&lt;li>Como padrão, use &lt;strong>&lt;code>std::unique_ptr&lt;/code>&lt;/strong> sempre, e incorpore no design a sua clara propriedade de exclusividade enquanto ganha as vantagens de ter zero overhead.&lt;/li>
&lt;li>Use o &lt;strong>&lt;code>std::shared_ptr&lt;/code>&lt;/strong> apenas caso seja verdadeiramente necessário compartilhar o ciclo de vida entre vários proprietários, e utilize o &lt;code>std::make_shared&lt;/code> para instanciá-lo.&lt;/li>
&lt;li>Faça bom uso do &lt;strong>&lt;code>std::weak_ptr&lt;/code>&lt;/strong> para a implementação do padrão de observador (Observer Pattern) e estruturas de dados que tendem a causar ciclos na propriedade (referências circulares), para, assim, prevenir vazamentos de memória antes que eles aconteçam.&lt;/li>
&lt;/ol>
&lt;p>Através do profundo entendimento dos smart pointers e de suas corretas aplicações nos lugares adequados, torna-se possível erguer uma arquitetura de software segura e sólida sem abrir mão de nenhuma das partes da alta performance da linguagem C++.&lt;/p></description></item></channel></rss>