Ajude nosso projeto a se manter online.

Alocação Dinâmica de Memória e o Operador new e delete

Neste tutorial, vamos aprender uma nova maneira de declarar variáveis, usando o operador new e ponteiros, em C++.

Alocação Dinâmica de Memória

Vamos supor que você vai fazer um software para a multinacional que você trabalha.
Ela tem 1000 empregados.

Então, você vai declarar, dentre várias coisas, mil variáveis do tipo int para armazenar a idade de cada pessoa, mil variáveis do tipo double para armazenar o salário de cada um, mil strings para armazenar o nome de cada um, etc, etc.

Porém, sua empresa cresceu, e agora tem 2 mil funcionários.
E agora, volta lá no código e muda tudo?

Até o momento, em nosso curso de C++, declaramos valores fixos, valores exatos de blocos de memória, mas isso nem sempre é interessante, no mundo da computação. Muitas vezes você não sabe quantas variáveis vai precisar usar, logo não sabe quantas variáveis vai precisar declarar.

Por exemplo, se você for criar uma nova rede social, quanto espaço de memória vai precisar para armazenar os dados dos usuários? Ué, não sabe...afinal, pode ter mil ou 1 milhão de usuários, quem sabe.

O que você tem que fazer é, então, alocar memória dinamicamente. Ou seja, vai alocar a medida que for precisando.

Ponteiros e o Operador new

Vamos supor que você queira alocar espaço para uma variável do tipo double.
Você vai pedir, via código C++, para o computador que ele ache um bloco de memória na máquina que seja possível alocar para você, que esteja livre.

Ele então vai lá vasculhar no seu sistema, acha um bloco e te devolve o endereço inicial desse bloco, o endereço do primeiro byte. Ora, se ele te devolve um endereço, o que você precisa para guardar esse tipo de informação?

Sim, nosso amado tipo de ponteiro.

Esse pedido de alocação é feito com o operador new.
Veja um exemplo de código que alocamos um bloco de memória para uma variável do tipo double:
#include <iostream>
using namespace std;

int main()
{
    double *ptr;
    ptr = new double;
    *ptr = 3.14;

    cout << *ptr << endl;

    return 0;
}
Quando digitamos 'new double', a máquina devolve um endereço de memória, o primeiro do bloco reservado para o double, e armazena esse endereço no ponteiro 'ptr', que obviamente deve ser do tipo double também (ou seja, aponta para o endereço inicial de um bloco de 8 Bytes, espaço necessário para um double).

Veja, não definimos nenhuma variável puramente do tipo double. Temos apenas um ponteiro que aponta para um bloco que tem um valor do tipo double.

Podemos, inclusive alterar esse valor armazenado, usando *ptr:
#include <iostream>
using namespace std;

int main()
{
    double *ptr;
    ptr = new double;
    cin >> *ptr;

    cout << *ptr << endl;

    return 0;
}
Tudo que poderíamos fazer com uma variável do tipo double, podemos fazer com esse ponteiro.

Podemos também alocar arrays inteiros, com o operador new, veja:
#include <iostream>
using namespace std;

int main()
{
    int *ptr;
    ptr = new int[10];

    for(int aux=0 ; aux<10 ; aux++){
        ptr[aux] = aux+1;
    }

    for(int aux=0 ; aux<10 ; aux++){
        cout << ptr[aux] << endl;
    }

    return 0;
}
No código acima, alocamos um array de 10 inteiros, e preenchemos com os números de 1 até 10.
Ou seja, no primeiro exemplo, ptr 'virou' um double. Nesse exemplo de cima, ptr 'virou' um array de inteiros.

Flexíveis esses ponteiros, não são?

Liberando espaços de memória - Operador delete

Outra vantagem de usar alocação de memória dinamicamente, é a possibilidade de liberar também essa memória que foi alocada, bastando usar o operador delete.

No primeiro exemplo, desalocamos o bloco de memória assim:
#include <iostream>
using namespace std;

int main()
{
    double *ptr;
    ptr = new double;
    cin >> *ptr;

    cout << *ptr << endl;

    delete ptr;

    return 0;
}
No caso dele ser um array, colocamos o par de colchetes [ ] antes do nome do ponteiro:
#include <iostream>
using namespace std;

int main()
{
    int *ptr;
    ptr = new int[10];

    for(int aux=0 ; aux<10 ; aux++){
        ptr[aux] = aux+1;
    }

    for(int aux=0 ; aux<10 ; aux++){
        cout << ptr[aux] << endl;
    }

    delete [] ptr;

    return 0;
}
Isso pode parecer bobagem hoje em dia, se imaginar seu PC com vários e vários Terabytes, não é preciso ficar liberando memória alocada, durante a execução de um programa.

Porém, esse conhecimento e prática é essencial em sistemas críticos que consomem muita memória, como em um jogo de altíssimo nível ou em um sistema operacional, super eficiente, não pode deixar tudo alocado pra sempre, tem que ir liberando aos poucos.

Já em sistemas com pouco espaço de memória (como seu relógio digital, o painel de uma geladeira ou o timer de seu microondas), é vital ir desalocando e liberando memória, pois esse recurso é super escasso.

Estudaremos com mais detalhes o operador new quando estudarmos Classes e Objetos, em Programação Orientada à Objetos.

Nenhum comentário:

Postar um comentário