Programar em C++
141 pág.

Programar em C++


DisciplinaLinguagem de Programação Estruturada128 materiais1.053 seguidores
Pré-visualização34 páginas
Alocação dinâmica de memória 124
Operador Delete - Memory Leak
O tempo de vida de uma variável criada dinamicamente é o tempo de execução do programa. Se um ponteiro aponta
para uma variável dinâmica e fica out of scope, já não conseguiremos acessar essa memória criada dinamicamente.
Fica indisponível. A isso se chama Memory Leak
Explicando: se alocamos memória dinamicamente dentro de uma função usando um ponteiro local, quando a função
termina, o ponteiro será destruído, mas a memória mantém-se. Assim já não teríamos maneira de chamar essa
memória porque ela não tem nome! Apenas tínhamos o endereço que estava no ponteiro.
Portanto, se realmente não necessitamos mais dos dados que estão nessa memória dinâmica, em vez de eles estarem
a ocupar espaço vamos apagá-los! Necessitamos de libertar essa memória através do operador delete \u2013 este operador
entrega ao sistema operativo a memoria reservada dinamicamente.
A sintaxe é
 delete [] iPtr;
Este delete operator não apaga o ponteiro mas sim a memória onde o ponteiro aponta.
dynamic memory allocation funciona porque a memória não é reservada no momento da compilação, mas antes na
execução. Em vez de ser no STACK (compilação) a memória é reservada no HEAP (execução). O heap é uma parte
da memória que é usada como memória temporária.
Pergunta: onde é que fica situado o Heap?
Vamos explicar melhor todo este processo: pois isto tem de entrar na cabeça!!!
 void myfunction()
 {
 int *pt;
 int av;
 pt = new int(1024);
 ....
 ....
 //No delete
 } 
 int main()
 {
 while (some condition exists) // Pseudo-code
 {
 myfunction();
 }
 exit 0;
 }
quando a função \u201cmyfunction\u201d é chamada a variável \u201cav\u201d é criada no stack e quando a função acaba a variável é
retirada do stack. O mesmo acontece com o ponteiro pt, ele é uma variável local. ou seja quando a função acaba o
ponteiro também termina e é retirado do stack. Porém o objeto alocado dinamicamente ainda existe.
E agora não conseguimos apagar esse objeto por que ele não tem nome e a única maneira que tínhamos para saber
onde ele estava era através do ponteiro que terminou quando termina a função pois ele é local.
Então à medida que o programa continua a operar mais e mais memória será perdida do Heap (free store). se o
programa continuar o tempo suficiente, deixaremos de ter memória disponível e o programa deixará de operar.
Alocação dinâmica de memória 125
Retornando um ponteiro para uma variável local
 #include <iostream>
 using namespace std;
 char * setName();
 int main (void)
 {
 char* str = setName(); //ponteiros para a função
 cout << str; //imprimo o valor do ponteiros?
 system (\u201cpause\u201d);
 return 0;
 }
 char* setName (void)
 {
 char name[80]; 
 cout << &quot;Enter your name: &quot;;
 cin.getline (name, 80);
 return name;
 }
O que se passou aqui é que o ponteiro que sai da função setName aponta para o array local cuja vida acaba quando a
função termina de executar. A solução é estender o tempo de vida. Uma solução era tornar esse array global, mas
existem alternativas melhores.
Retornando um Ponteiro a uma Variável Local Estática
Uma dessas alternativas é
 #include <iostream>
 using namespace std;
 char * setName();
 int main (void)
 {
 char* str = setName();
 cout << str;
 system (\u201cpause\u201d);
 return 0;
 }
 char* setName (void)
 {
 static char name[80]; //crio como static
 cout << &quot;Enter your name: &quot;;
 cin.getline (name, 80);
 return name;
 }
A diferença é que usamos a palavra static.
O ponteiro do setName aponta para o array local, e como foi utilizado o static, ele perdura até fim da função,
terminando apenas quando o programa acaba.
Alocação dinâmica de memória 126
Returning a Pointer to a Dynamically Created Variable
Outra alternative, talvez melhor
 #include <iostream>
 using namespace std;
 char * setName();
 int main (void)
 {
 char* str= setName();
 cout << str;
 delete [] str; //faço o delete para evitar o memory leak
 system (&quot;pause&quot;);
 return 0;
 }
 char* setName (void)
 {
 char* name = new char[80]; //crio ponteiro chamado de name e dou 
o valor do endereço da memoria dinâmica
 cout << &quot;Enter your name: &quot;;
 cin.getline (name, 80);
 return name;
 }
Isto funciona porque o ponteiro retornado da função setname aponta para o array cujo tempo de vida persiste. O
address do ponteiro local é atribuído no main a outro ponteiro no main \u2013str. Depois este ponteiro é usado até ao fim
da execução do programa. Este é um exemplo onde diferentes ponteiros apontam para o mesmo endereço.
Mas ter atenção que se fizermos o delete através de um ponteiro, ter cuidado com o segundo ponteiro que aponta
para a memoria que acabou de ser deslocada.
Alocar dinamicamente Arrays
Ora o que fizemos antes com variáveis, vamos ter de fazer com arrays.
 int *pt = new int[1024]; //allocates an array of 1024 ints
 double *myBills = new double[10000]; 
 /* This doesn't mean I owe 10000.0, but rather allocates an array of 
10000 doubles to hold the amounts of the thousands of bills I receive 
monthly. */
Notar a diferença:
 int *pt = new int[1024]; //allocates an array of 1024 ints
 int *pt = new int(1024); //allocates a single int with value 1024
a melhor maneira para alocar um array dinamicamente é usar o loop
 int *buff = new int[1024];
 for (i = 0; i < 1024; i++) 
 {
 *buff = 52; //Assigns 52 to each element;
 buff++;
Alocação dinâmica de memória 127
 }
 ou se quisermos desta maneira
 int *buff = new int[1024];
 for (i = 0; i < 1024; i++) 
 {
 buff[i] = 52; //Assigns 52 to each element;
 }
para utilizar o delete em arrays
 delete[] pt;
 delete[] myBills; 
Dangling Pointers
 int *myPointer;
 myPointer = new int(10);
 cout << &quot;The value of myPointer is &quot; << *myPointer << endl;
 delete myPointer;
 *myPointer = 5;
 cout << &quot;The value of myPointer is &quot; << *myPointer << endl;
neste exemplo libertámos a memória dinâmica, mas o ponteiro continua isto é um bug tremendo, e muito difícil de
detectar. o programa continua a correr e a secção de memória pode ser usada por outro objeto dinâmico. acontece
que essa memoria estará corrompida se continuar a usar o myPointer. a melhor maneira é depois do delete fazer
apontar para zero, fazê-lo um ponteiro nulo. se tentarem usar o ponteiro iremos ter a run time exception e o bug pode
ser identificado
Assim, corrigindo o código anterior ficaríamos com:
 int *myPointer;
 myPointer = new int(10);
 cout << &quot;The value of myPointer is &quot; << *myPointer << endl;
 delete myPointer;
 myPointer = 0;
 *myPointer = 5; //This statement will cause an run-time exception, 
now.
 cout << &quot;The value of myPointer is &quot; << *myPointer << endl;
Verificar a existência de memória para dinâmica
Na alocação dinâmica temos de nos certificar de que a alocação no heap foi feita com sucesso e podemos ver isso de
duas maneiras:
\u2022\u2022 Uma são as exceções (este é o método defaut)
 bobby = new int [5]; // if it fails an exception is thrown 
\u201cbad_alloc\u201d exception
vamos ver este caso quase no ultimo capitulo- isto é uma capítulo avançado
\u2022\u2022 notthrow, aqui no caso de não se conseguir a memória retorna um ponteiro nulo, e o programa continua.
 bobby = new (nothrow) int [5];
Alocação dinâmica de memória 128
supostamente este método pode ser tedioso para grandes projetos
Vamos ver um exemplo com o caso de nothrow
 // rememb-o-matic
 #include <iostream>
 using namespace std;
 int main ()
 {
 int i,n,* p;
 cout << &quot;How many numbers would you like to type? &quot;;
 cin >> i;
 p= new (nothrow) int[i]; //criámos I variaveis na execução