{"id":1984,"date":"2022-02-27T23:29:55","date_gmt":"2022-02-28T02:29:55","guid":{"rendered":"https:\/\/elemarjr.com\/cppmoderno\/?p=1984"},"modified":"2025-06-18T16:07:12","modified_gmt":"2025-06-18T19:07:12","slug":"gestao-de-memoria-em-c-e-insegura-onde-apendice-b-v-1-0","status":"publish","type":"post","link":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/gestao-de-memoria-em-c-e-insegura-onde-apendice-b-v-1-0\/","title":{"rendered":"Heap ou Stack? O programador decide! \/\/ Ap\u00eandice B v 1.0"},"content":{"rendered":"<p>Para programadores C++, performance \u00e9 algo muito importante! <strong>Qualquer pessoa com experi\u00eancia razo\u00e1vel desenvolvendo sistemas perform\u00e1ticos sabe que o &#8220;segredo do sucesso&#8221; est\u00e1 no uso racional de recursos, sobretudo da mem\u00f3ria. Por isso, C++ d\u00e1 controle total desse\u00a0aspecto ao programador.\u00a0<\/strong><\/p>\n<p>Grandes poderes, entretanto, demandam grandes responsabilidades. No passado, C++, embora poderosa, n\u00e3o facilitava a escrita de programas, ao mesmo tempo, seguros e perform\u00e1ticos. Entretanto, tudo mudou desde o surgimento e a populariza\u00e7\u00e3o de alternativas como\u00a0<em>smart pointers.<\/em><\/p>\n<p>Nesse ap\u00eandice, mostro algumas op\u00e7\u00f5es dispon\u00edveis para que o programador determine o comportamento de um programa com rela\u00e7\u00e3o a mem\u00f3ria.<\/p>\n<h2><em>Heap\u00a0<\/em>ou\u00a0<em>Stack<\/em>? Sempre uma escolha do programador<\/h2>\n<p>Em C++, cabe ao programador decidir se valores, incluindo inst\u00e2ncias de classes, ser\u00e3o alocados na\u00a0<em>stack<\/em> ou na\u00a0<em>heap.<\/em><\/p>\n<div class=\"card-insight\" style=\"background-color: #f0f0f0; width: 100%; padding: 35px 30px 20px 35px; border-radius: 5px 5px 5px 5px; margin-top: 30px; margin-bottom: 35px; font-size: 16px; box-shadow: 0px 4px 0px 0px #dddddd;\">\r\n<p style=\"font-size: 24px; font-weight:bold; line-height: 28px; font-family: Lufga;\">O que \u00e9 a <em>Stack<\/em>?<\/p>\r\n<\/p>\n<p>Pilhas s\u00e3o regi\u00f5es de mem\u00f3ria onde os dados s\u00e3o adicionados ou removidos de maneira LIFO (<em>last-in-first-out<\/em>).<\/p>\n<p>Cada <em>thread\u00a0<\/em>em um processo em execu\u00e7\u00e3o,\u00a0tem uma regi\u00e3o reservada de mem\u00f3ria chamada de <em>stack<\/em>. Quando uma fun\u00e7\u00e3o \u00e9 executada, ela pode adicionar alguns de seus &#8220;dados locais ao topo da pilha; quando a fun\u00e7\u00e3o sai, ela \u00e9 respons\u00e1vel por remover esses dados da pilha. <\/div>\n<p>Um\u00a0objeto alocado na\u00a0<em>stack <\/em>\u00e9\u00a0&#8220;destru\u00eddo&#8221; e removido da mem\u00f3ria automaticamente, sempre que o escopo da <em>stack\u00a0<\/em>onde est\u00e1 alocado\u00a0\u00e9 encerrado.<\/p>\n<pre>#include &lt;iostream&amp;gt\r\n#include &lt;memory&amp;gt\r\n\r\nclass Fraction {\r\nprivate:\r\n  int _numerator;\r\n  int _denominator;\r\n\r\npublic:\r\n  Fraction(int numerator, int denominator) \r\n    : _numerator(numerator), _denominator(denominator) {\r\n    std::cout &lt;&lt; \"Custom ctor invoked.\" &lt;&lt; std::endl;\r\n  }\r\n\r\n  ~Fraction() {\r\n    std::cout &lt;&lt; \"Fraction instance destructed.\" &lt;&lt; std::endl;\r\n  }\r\n};\r\n\r\nint main() {\r\n  auto fa = Fraction(2, 3); \/\/ Fraction\r\n  std::cout &lt;&lt; \"Goodbye, cruel!\" &lt;&lt; std::endl;\r\n\r\n  return 0;\r\n}\r\n\r\n\/\/ OUTPUT:\r\n\/\/ Custom ctor executed.\r\n\/\/ Goodbye, cruel!\r\n\/\/ Fraction instance destructed.\r\n<\/pre>\n<p>Tradicionalmente, a aloca\u00e7\u00e3o de objetos na\u00a0<em>heap\u00a0<\/em>acontecia mediante a utiliza\u00e7\u00e3o do operador <code>new<\/code>. Objetos alocados na\u00a0<em>heap\u00a0<\/em> dessa maneira dever\u00e3o ser &#8220;destru\u00eddos&#8221; e desalocados atrav\u00e9s da utiliza\u00e7\u00e3o do operador <code>delete<\/code>.<\/p>\n<div class=\"card-insight\" style=\"background-color: #f0f0f0; width: 100%; padding: 35px 30px 20px 35px; border-radius: 5px 5px 5px 5px; margin-top: 30px; margin-bottom: 35px; font-size: 16px; box-shadow: 0px 4px 0px 0px #dddddd;\">\r\n<p style=\"font-size: 24px; font-weight:bold; line-height: 28px; font-family: Lufga;\">O que \u00e9 a <em>Heap<\/em>?<\/p>\r\n<\/p>\n<p><em>Heap\u00a0<\/em>\u00e9 o nome do espa\u00e7o de mem\u00f3ria utilizado por um programa para aloca\u00e7\u00e3o de dados dinamicamente, geralmente com espa\u00e7o determinado em tempo de execu\u00e7\u00e3o.<\/div>\n<pre>int main() {\r\n  auto fa = new Fraction(2, 3); \/\/ Fraction*\r\n  std::cout &lt;&lt; \"Goodbye, cruel!\" &lt;&lt; std::endl;\r\n  delete fa;\r\n  return 0;\r\n}\r\n\r\n\/\/ OUTPUT:\r\n\/\/ Custom ctor executed.\r\n\/\/ Goodbye, cruel!\r\n\/\/ Fraction instance destructed.\r\n<\/pre>\n<p>Modernamente, entretanto, recomenda-se a utiliza\u00e7\u00e3o de <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/memory\">smart pointers<\/a>.<\/p>\n<pre>int main() {\r\n  auto fa = new std::make_unique&lt;Fraction&gt;(2, 3); \/\/ unique_ptr&lt;Fraction&gt;\r\n  std::cout &lt;&lt; \"Goodbye, cruel!\" &lt;&lt; std::endl;\r\n  return 0;\r\n}\r\n\r\n\/\/ OUTPUT:\r\n\/\/ Custom ctor executed.\r\n\/\/ Goodbye, cruel!\r\n\/\/ Fraction instance destructed.\r\n<\/pre>\n<p><strong>A famosa &#8220;inseguran\u00e7a&#8221; na gest\u00e3o de mem\u00f3ria frequentemente associada a C++ tem rela\u00e7\u00e3o direta com a utiliza\u00e7\u00e3o dos operadores <code>new<\/code> e <code>delete<\/code>. Hoje em dia, essa pr\u00e1tica \u00e9 considerada um\u00a0<em>anti-pattern<\/em>.<\/strong><\/p>\n<h2>Implica\u00e7\u00f5es em alocar objetos na <em>Stack<\/em><\/h2>\n<p>Objetos alocados na\u00a0<em>stack\u00a0<\/em>s\u00e3o acessados de maneira mais r\u00e1pida e s\u00e3o desalocados automaticamente e de maneira determinista, sempre que um contexto \u00e9 encerrado. Entretanto, \u00e9 importante que se considere que a\u00a0<em>stack\u00a0<\/em>tem tamanho limitado e n\u00e3o \u00e9 apropriada para objetos com tamanhos vari\u00e1veis determinados em tempo de execu\u00e7\u00e3o.<\/p>\n<p>Por padr\u00e3o, sempre uma vari\u00e1vel aponta para um valor presente na\u00a0<em>stack\u00a0<\/em>uma c\u00f3pia \u00e9 realizada.<\/p>\n<pre>int main() {\r\n  auto fa = Fraction(2, 3);\r\n  auto fb = fa;\r\n  std::cout &lt;&lt; \"Goodbye, cruel!\" &lt;&lt; std::endl;\r\n\r\n  return 0;\r\n}\r\n\r\n\/\/ OUTPUT:\r\n\/\/ Custom ctor executed.\r\n\/\/ Goodbye, cruel!\r\n\/\/ Fraction instance destructed.\r\n\/\/ Fraction instance destructed.\r\n<\/pre>\n<p>No c\u00f3digo acima, o construtor fornecido \u00e9 chamado apenas uma vez. Entretanto, o destrutor \u00e9 chamado duas vezes. Na pr\u00e1tica, quando a atribui\u00e7\u00e3o para <code>fb<\/code> acontece, um construtor especial (de c\u00f3pia) \u00e9 executado copiando dados. O programador tem liberdade para implementar o <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/copy_constructor\">construtor de c\u00f3pia<\/a> se desejar.<\/p>\n<pre>#include &lt;iostream&gt;\r\n\r\nclass Fraction {\r\nprivate:\r\n  int _numerator;\r\n  int _denominator;\r\n\r\npublic:\r\n  Fraction(int numerator, int denominator)\r\n     : _numerator(numerator), _denominator(denominator) {\r\n    std::cout &lt;&lt; \"Custom ctor executed.\" &lt;&lt; std::endl;\r\n  }\r\n\r\n  \/\/ COPY CONSTRUCTOR\r\n  Fraction(const Fraction&amp; other)\r\n     : _numerator(other._numerator), _denominator(other._denominator) {\r\n    std::cout &lt;&lt; \"Copy ctor executed.\" &lt;&lt; std::endl;\r\n  }\r\n\r\n  int get_numerator() const {\r\n    return _numerator;\r\n  }\r\n\r\n  int get_denominator() const {\r\n    return _denominator;\r\n  }\r\n\r\n  ~Fraction() {\r\n    std::cout &lt;&lt; \"Fraction instance destructed.\" &lt;&lt; std::endl;\r\n  }\r\n};\r\n\r\nint main() {\r\n  auto fa = Fraction(2, 3); \/\/ Fraction\r\n  auto fb = fa;\r\n  std::cout &lt;&lt; \"Goodbye, cruel!\" &lt;&lt; std::endl;\r\n\r\n  return 0;\r\n}\r\n\r\n\/\/ OUTPUT:\r\n\/\/ Custom ctor executed.\r\n\/\/ Copy ctor executed.\r\n\/\/ Goodbye, cruel!\r\n\/\/ Fraction instance destructed.\r\n\/\/ Fraction instance destructed.\r\n<\/pre>\n<p>Uma alternativas para impedir c\u00f3pias desnecess\u00e1rias \u00e9 utilizando refer\u00eancias.<\/p>\n<pre>int do_something(const Fraction&amp; f) {\r\n  std::cout &lt;&lt; f.get_numerator() &lt;&lt; std::endl;\r\n}\r\n\r\nint main() {\r\n  auto fa = Fraction(2, 3); \/\/ Fraction\r\n\r\n  auto fb = &amp;fa;            \/\/ Fraction* - no copy\r\n  do_something(fa);         \/\/ passing by reference - no copy\r\n  std::cout &lt;&lt; \"Goodbye, cruel!\" &lt;&lt; std::endl;\r\n\r\n  return 0;\r\n}\r\n<\/pre>\n<h2>Implica\u00e7\u00f5es em alocar objetos na <em>Heap<\/em><\/h2>\n<p>Diferente do que \u00e9 dito com frequ\u00eancia, a utiliza\u00e7\u00e3o da\u00a0<em>heap\u00a0<\/em>n\u00e3o \u00e9 a \u00fanica (nem a melhor) alternativa para impedir a c\u00f3pia (e multiplica\u00e7\u00e3o de inst\u00e2ncias) de dados, t\u00e3o caracter\u00edstica quando objetos s\u00e3o alocados na\u00a0<em>stack<\/em>.<\/p>\n<p><strong>A aloca\u00e7\u00e3o din\u00e2mica de mem\u00f3ria deve ser usada sempre que o volume de mem\u00f3ria demandado n\u00e3o for poss\u00edvel de determinar durante o tempo de compila\u00e7\u00e3o.<\/strong> Por exemplo, o tamanho de um <em>array\u00a0<\/em>que armazenar\u00e1 dados de acordo com entradas de dados de usu\u00e1rios.<\/p>\n<p>Modernamente, aloca\u00e7\u00e3o de mem\u00f3ria din\u00e2mica em C++ acontece atrav\u00e9s de\u00a0<em>smart pointers\u00a0<\/em>, implementa\u00e7\u00e3o de uma varia\u00e7\u00e3o de uma t\u00e9cnica popular conhecida como RAII.<\/p>\n<div class=\"card-insight\" style=\"background-color: #f0f0f0; width: 100%; padding: 35px 30px 20px 35px; border-radius: 5px 5px 5px 5px; margin-top: 30px; margin-bottom: 35px; font-size: 16px; box-shadow: 0px 4px 0px 0px #dddddd;\">\r\n<p style=\"font-size: 24px; font-weight:bold; line-height: 28px; font-family: Lufga;\">RAII<\/p>\r\n<\/p>\n<p>RAII &#8211; <em>resource acquisition is initialization\u00a0<\/em>\u00e9 uma t\u00e9cnica onde a ideia b\u00e1sica \u00e9 representar o recurso que se deseja controlar em um objeto local (na <em>stack<\/em>)\u00a0de forma que o destrutor deste objeto fique respons\u00e1vel por, eventualmente, liberar tal recurso se poss\u00edvel.<\/p>\n<p><\/div>\n<p class=\"q-text qu-display--block qu-wordBreak--break-word qu-textAlign--start\">H\u00e1 duas implementa\u00e7\u00f5es principais de\u00a0<em>smart pointers\u00a0<\/em>no C++: <code>unique_ptr<\/code>\u00a0e <code>shared_ptr<\/code>.<\/p>\n<p><code>unique_ptr<\/code>\u00a0\u00e9 uma alternativa ultra-leve para quando um objeto, alocado dinamicamente, tiver apenas um \u00fanico &#8220;consumidor&#8221;. Na pr\u00e1tica, ele dispensa que programadores se preocupem em realizar a &#8220;desaloca\u00e7\u00e3o&#8221; de objetos manualmente, impedindo a ocorr\u00eancia de\u00a0<em>leaks<\/em>. Trata-se de uma implementa\u00e7\u00e3o econ\u00f4mica que desautoriza c\u00f3pias.<\/p>\n<p><code>shared_ptr<\/code>, por outro lado, \u00e9 destinado para cen\u00e1rios onde diversos &#8220;consumidores&#8221; t\u00eam interesse em um mesmo objeto e compartilham a responsabilidade pela &#8220;desaloca\u00e7\u00e3o&#8221;. Apenas quando todas as inst\u00e2ncias do <em>smart pointer\u00a0<\/em>forem descartadas, ent\u00e3o, o objeto controlado \u00e9 descartado. Trata-se de uma op\u00e7\u00e3o segura, inclusive para c\u00f3digo concorrente (<em>multi-thread<\/em>)<\/p>\n<p>Tanto\u00a0<code>shared_ptr<\/code> quanto\u00a0<code>unique_ptr<\/code>\u00a0foram projetados para serem passados &#8220;por valor&#8221;.<\/p>\n<pre>#include &lt;iostream&gt;\r\n#include &lt;memory&gt;\r\n\r\nclass A {\r\nprivate:\r\n  int _value {};\r\n\r\npublic:\r\n  void set_value(int newValue)  {\r\n      _value = newValue;\r\n  }\r\n\r\n  int get_value() const { return _value; }\r\n\r\n  A() { std::cout &lt;&lt; \"A::A()\" &lt;&lt; std::endl; }\r\n  ~A() { std::cout &lt;&lt; \"A::~A()\" &lt;&lt; std::endl; }\r\n\r\n  void say_value()  { std::cout &lt;&lt; \"hello \" &lt;&lt; _value &lt;&lt; \"!\" &lt;&lt; std::endl; }\r\n};\r\n\r\n\r\nvoid do_something(std::shared_ptr&lt;A&gt; a) {\r\n  a-&gt;set_value(10);\r\n}\r\n\r\nint main() {\r\n  auto a = std::make_shared&lt;A&gt;();\r\n  do_something(a);\r\n  a-&gt;say_value();\r\n}\r\n\r\n\/\/ OUTPUT:\r\n\/\/ A::A()\r\n\/\/ hello 10!\r\n\/\/ A::~A()\r\n<\/pre>\n<p>No c\u00f3digo acima, a inst\u00e2ncia alocada em <code>main<\/code> \u00e9 destru\u00edda e desalocada automaticamente quando o programa \u00e9 encerrado.<\/p>\n<pre class=\"erro\">int main() {\r\n    auto a = std::make_unique&lt;A&gt;();\r\n    auto b = a; \/\/ fail to copy.\r\n}\r\n<\/pre>\n<p>J\u00e1 o c\u00f3digo acima, n\u00e3o compila porque o <em>smart pointer<\/em> <code>unique_ptr<\/code> foi implementado de forma a n\u00e3o permitir c\u00f3pias. Para fazer &#8220;transfer\u00eancia de <em>ownership<\/em>&#8221; deve-se recorrer a movimenta\u00e7\u00e3o expl\u00edcita (utilizando <code>std::move<\/code>).<\/p>\n<pre>int main() {\r\n    auto a = std::make_unique<a>();\r\n    auto b = std::move(a);\r\n\r\n    assert(!a);\r\n    assert(b);\r\n}\r\n<\/a><\/pre>\n<h2>Inseguro? Onde?<\/h2>\n<div class=\"nota-alerta\">\r\n<table class=\"tabelaalerta\" style=\"width: 100%;\">\r\n<tbody>\r\n<tr>\r\n<td class=\"nota-coluna-1\" valign=\"top\"><img decoding=\"async\" class=\"img-citacao\" src=\"\/cppmoderno\/wp-content\/uploads\/2021\/11\/ico-citacao-2-1.png\" alt=\"\" width=\"60\" height=\"60\" \/><\/td>\r\n<td class=\"nota-coluna-2\"><img decoding=\"async\" class=\"nota-img\" src=\"\/cppmoderno\/wp-content\/uploads\/2021\/11\/ico-citacao-2-1.png\" alt=\"\" width=\"60\" height=\"60\" \/> &#8220;Legacy code&#8221; often differs from its suggested alternative by actually working and scaling.\r\n<p><strong>Bjarne Stroustrup<\/strong><\/p>\r\n<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n<\/div>\n<p>C\u00f3digo legado C++ pode ser dif\u00edcil de manter, principalmente pela dificuldade de gerenciar o ciclo de vida de objetos utilizando os operadores <code>new<\/code> e <code>delete<\/code>. Mas, com o advento dos\u00a0<em>smart pointers<\/em> isso parece ser coisa do passado.<\/p>\n<p>Discorda?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Para programadores C++, performance \u00e9 algo muito importante! Qualquer pessoa com experi\u00eancia razo\u00e1vel desenvolvendo sistemas perform\u00e1ticos sabe que o &#8220;segredo do sucesso&#8221; est\u00e1 no uso racional de recursos, sobretudo da mem\u00f3ria. Por isso, C++ d\u00e1 controle total desse\u00a0aspecto ao programador.\u00a0 Grandes poderes, entretanto, demandam grandes responsabilidades. No passado, C++, embora poderosa, n\u00e3o facilitava a escrita [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":2031,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"hashtags":[],"tipo":[39],"url":[37],"apendices":[34],"capitulos":[],"class_list":["post-1984","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tipo-apendice","url-permanente","apendices-apendice-b"],"_links":{"self":[{"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/posts\/1984","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/comments?post=1984"}],"version-history":[{"count":51,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/posts\/1984\/revisions"}],"predecessor-version":[{"id":2065,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/posts\/1984\/revisions\/2065"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/media\/2031"}],"wp:attachment":[{"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/media?parent=1984"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/categories?post=1984"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/tags?post=1984"},{"taxonomy":"hashtags","embeddable":true,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/hashtags?post=1984"},{"taxonomy":"tipo","embeddable":true,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/tipo?post=1984"},{"taxonomy":"url","embeddable":true,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/url?post=1984"},{"taxonomy":"apendices","embeddable":true,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/apendices?post=1984"},{"taxonomy":"capitulos","embeddable":true,"href":"https:\/\/elemarjr.com\/livros\/cpp-moderno\/wp-json\/wp\/v2\/capitulos?post=1984"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}