O programador é responsável por garantir que os objetos criados por meio de new
sejam excluídos via delete
. Se um objeto é criado, mas não destruído antes que o último ponteiro ou referência a ele saia do escopo, ele cai nas rachaduras e se torna um Vazamento de memória .
Infelizmente para C, C ++ e outras linguagens que não incluem um GC, isso simplesmente se acumula com o tempo. Isso pode fazer com que um aplicativo ou o sistema fique sem memória e não consiga alocar novos blocos de memória. Neste ponto, o usuário deve recorrer ao encerramento do aplicativo para que o sistema operacional possa recuperar a memória usada.
No que diz respeito a atenuar este problema, existem várias coisas que tornam a vida de um programador muito mais fácil. Eles são suportados principalmente pela natureza do escopo .
int main()
{
int* variableThatIsAPointer = new int;
int variableInt = 0;
delete variableThatIsAPointer;
}
Aqui, criamos duas variáveis. Eles existem no Block Scope , conforme definido pelas chaves {}
. Quando a execução se move para fora desse escopo, esses objetos serão excluídos automaticamente. Nesse caso, variableThatIsAPointer
, como o próprio nome indica, é um ponteiro para um objeto na memória. Quando ele sai do escopo, o ponteiro é excluído, mas o objeto para o qual ele aponta permanece. Aqui, nós delete
este objeto antes de sair do escopo para garantir que não haja vazamento de memória. No entanto, poderíamos ter passado este ponteiro para outro lugar e esperado que ele fosse apagado mais tarde.
Essa natureza do escopo se estende a classes:
class Foo
{
public:
int bar; // Will be deleted when Foo is deleted
int* otherBar; // Still need to call delete
}
Aqui, o mesmo princípio se aplica. Não precisamos nos preocupar com bar
quando Foo
for excluído. No entanto, para otherBar
, apenas o ponteiro é excluído. Se otherBar
for o único ponteiro válido para qualquer objeto para o qual ele aponta, devemos provavelmente delete
em% debug% s. Este é o conceito de direção por trás do RAII
resource allocation (acquisition) is done during object creation (specifically initialization), by the constructor, while resource deallocation (release) is done during object destruction (specifically finalization), by the destructor. Thus the resource is guaranteed to be held between when initialization finishes and finalization starts (holding the resources is a class invariant), and to be held only when the object is alive. Thus if there are no object leaks, there are no resource leaks.
O RAII também é a força motriz típica por trás dos Ponteiros inteligentes . Na C ++ Standard Library, estes são Foo
, std::shared_ptr
e std::unique_ptr
; embora eu tenha visto e usado outras implementações std::weak_ptr
/ shared_ptr
que seguem os mesmos conceitos. Para estes, um contador de referência controla quantos ponteiros existem para um determinado objeto e automaticamente weak_ptr
s o objeto, uma vez que não há mais referências a ele.
Além disso, tudo se resume a práticas e disciplina adequadas para um programador garantir que seu código manipule objetos adequadamente.