Alocação de desalocação de memória em C++

Olá, estou com uma dúvida em alocação e desalocação de memória. Segue o código abaixo.

/Dynamic Allocation of integer numbers/
#include
using namespace std;

int main()
{
int *pointer_N = new int;
cout << "How many integers do you want me to store? ";
cin >> *pointer_N;

int *int_Array = new int[*pointer_N];

cout << "Your Array is: \n\n              [ ";
for (int i = 0; i < *pointer_N; i++)
{
    int_Array[i] = i + 1;
    cout << int_Array[i];
    if (i < *pointer_N - 1)
    cout << ", ";
}

cout << " ]\n\n";

delete pointer_N;
delete[] int_Array;

cout << "\n\n"<< *pointer_N;
cout << "\n\n"<< int_Array[0];
cout << "\n\n"<< int_Array[0];
cout << "\n\n"<< int_Array[3];
return 0;

}

No código acima eu aloco um array dinâmicamente e no fim eu deleto utilizando o operador delete. No texte com 10 ou mais elementos noto que apenas os indices 0 e 1 do array voltam a guardar lixos de memória. Do indice 3 em diante os valores antes colocados ainda estão lá. Tanto que eu consigo acessar. Alguém saberia explicar esse comportamento? Dei uma pesquisada e todos os lugares dizem que o operador delete realmete deleta todo o conteúdo do array.

Imagem da execução.
Photo

Obs: Eu esse comportamento ocorre desalocando todo o array com delete[ ] e desalocando cada elemeto de cada vez.

O comportamento do delete parece estar ligado com o tipo de compilador utilizado. Esse seu código apresentou resultados diferentes em sites de C++ Compiler.

Your Array is: 

              [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]



1550594877

1550594878

1550594878

-125902469
Your Array is: 

[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]



0

0

0

0
Your Array is: 

              [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]



1235627320

1

1

4
1 curtida

De forma bem resumida, delete não “limpa” o conteúdo de nada. Ele só desaloca memória, indicando que ela não está mais disponível para ser usada. Mas a linguagem não impede que vc tente acessar a memória que foi desalocada. O detalhe é que pode ser que isso “funcione”, pode ser que não - já que acessar memória desalocada gera um comportamento indefinido (o famoso “UB” - Undefined Behaviour).

Tem uma explicação bem detalhada aqui e aqui. Tomei a liberdade de traduzir/adaptar um trecho, que achei bem didático:

Você reserva um quarto de hotel, coloca um livro na gaveta do criado-mudo ao lado da cama e vai dormir. No dia seguinte vc faz o check out, mas “esquece” de devolver a chave. Vc rouba a chave!

Uma semana depois, vc volta ao hotel (sem reserva), não faz o check in, vai até o mesmo quarto, entra usando sua chave roubada, e olha na gaveta. Seu livro ainda está lá. Uau!

Como isso é possível? As coisas que estavam na gaveta não ficam inacessívels para quem não reservou o quarto?

Bem, obviamente isso pode acontecer no mundo real sem problema. Não há uma força misteriosa que faz com que o livro suma caso vc não tenha mais autorização de entrar no quarto. Assim como não há uma força misteriosa que te impeça de entrar no quarto com uma chave roubada.

A gerência do hotel não é obrigada a retirar seu livro. Vc não fez um contrato com eles que diga que se algum objeto for deixado no quarto, eles devem triturá-lo. Se vc entrar ilegalmente no quarto com a chave roubada para pegar o livro de volta, a segurança do hotel não é obrigada a te capturar. Vc não fez um contrato que diz “se eu entrar naquele quarto, vcs devem me impedir”. Em vez disso, o contrato que vc tem com eles dizia “prometo não voltar a este quarto sem fazer uma nova reserva”, um contrato que vc quebrou.

Neste caso, qualquer coisa pode acontecer:

  • O livro pode estar lá - nesse caso, vc deu sorte.
  • O livro de outra pessoa pode estar lá, e o seu está no Achados & Perdidos do hotel.
  • Outra pessoa pode estar lá, rasgando seu livro em pedaços.
  • O hotel pode ter retirado o criado-mudo (e o livro) e colocado um armário no lugar.
  • O hotel pode ter sido demolido e no lugar construíram um estádio de futebol, e vc morre em uma explosão enquanto tentava encontrar o livro.

Vc não sabe o que pode acontecer. Quando vc saiu do hotel da primeira vez, com sua chave roubada para usar depois, vc abdicou do direito de viver em um mundo seguro e previsível, porque escolheu quebrar as regras do sistema.

C++ não é uma linguagem segura. Ela te deixa quebrar as regras do sistema. Se vc tentar algo ilegal e burro, como entrar em um quarto sem autorização, para fuçar uma gaveta que pode nem estar mais lá, C++ não vai te impedir. Linguagens mais seguras resolvem este problema restringindo seu poder - por exemplo, estabelecendo controles mais rígidos sobre a chave do quarto.

É isso. delete só avisa ao sistema operacional que a memória não está mais em uso, mas não necessariamente apaga o conteúdo dela. Ele é como o check out de um hotel preguiçoso, que nem sempre limpa o quarto depois que vc sai.

Se vc tentar acessar o mesmo endereço de memória depois de um delete, não é garantido que funcione (pode ou não ter o mesmo conteúdo, não há garantia nenhuma - e o comportamento pode inclusive variar de um compilador para outro, cada um pode implementar da maneira que bem entender).

E na verdade vc nem deveria fazer isso. Idealmente, tudo que é Undefined Behaviour deve ser evitado.

1 curtida

Obrigado pelas respostas, minha dúvida foi esclarecida, mas na verdade era mais uma curiosidade sobre o que acontecia com os endereços após a utilização do delete. Por isso eu apenas estava utilizando o cout para saber o que eles estavam guardando somente. Sim, em todos os lugares é consenso que o undefined behaviour deve ser evitado, como eu disse, era mais uma curiosidade. Agradeço novamente pelas respostas e pelo tempo dedicado à minha dúvida.