Manual
do
Maker
.
com
Antes de entrar no tema, preciso deixar claro que esse artigo sobre alocação de memória em C++ é uma continuação do artigo de ponteiros em C/C++, iniciado em uma lacuna entre os artigos agendados, razão pela qual a continuação demorou tanto para sair. E na verdade eu escrevi os dois no mesmo dia, só não quis publicá-los no mesmo dia por questão de aproveitamento e prazo para fazer vídeo. Continuando então de onde paramos.
Quando alocamos um ponteiro, reservamos um ponto de partida para outro endereço contendo os dados, não alocamos o espaço para esses dados. A criação do espaço de alocação é outra etapa do processo e deixar de fazê-lo acabará resultando em anomalias indetectáveis e aleatórias. Por essa razão, quando estiver desenvolvendo algo que envolva uma lógica com ponteiros tente experimentar em uma função à parte e tente criar testes unitários ou algo parecido.
Um exemplo de alocação no limbo:
#include <iostream>
#include <cstring>
using namespace std;
int main(){
uint8_t tamanho = 7;
cout << "exemplo 03" << endl;
char *myValue = (char *) malloc(tamanho * sizeof(char));
for (uint8_t i=0; i<7;i++){
cin >>myValue[i];
}
cout << myValue << endl;
int *teste;
*teste = 12345;
cout << teste << endl;
return 0;
}
O programa compilará sem erros nem avisos. Também executará, recolherá os valores de entrada mas, ao chegar no ponteiro teste as coisas ficarão estranhas; ou será exibido um valor estranho, ou haverá uma invasão de memória, ou pior: não acontecerá nada até que aconteça em um determinado fluxo. E esse tipo de problema é difícil depurar se for erro de lógica como esse.
Um ponteiro sempre descreve um endereço, portanto é um tipo de inteiro que não se utiliza para operações matemáticas. Um ponteiro para um inteiro sim.
Em C++ a alocação de memória é menos trabalhosa e mais descomplicada. Claro, o método do artigo de referência funciona em ambos, afinal, C++ é uma "carenagem" pro C (programadores C++ odeiam esse tipo de analogia).
int *ponteiro = new int;
Estamos dizendo que new deve alocar memória para um tipo int. A memória é reservada e o endereço é devolvido. A diferença é que agora para acessar a variável devemos referenciar o ponteiro, enquanto que alocando como exemplificado no primeiro artigo, acessamos pelo nome da variável. No C++ essa alocação resulta em um "objeto de dados". Não devemos confundir isso como um "objeto" de orientação da linguagem; é mais para "uma coisa", não simplesmente um número.
Para um único objeto de dados, a forma geral é essa:
<tipo> <nome> = <new tipo>
Um exemplo de uso é melhor que um exemplo teórico, então vamos lá:
Primeiro exibimos o valor atribuído, depois o endereço do ponteiro. No código fica assim:
#include <iostream>
using namespace std;
int main(){
cout << "exemplo 04" << endl;
int *ponteiro = new int;
*ponteiro = 100;
cout << "inteiro: ";
cout << *ponteiro << endl;
cout << "endereco: ";
cout << ponteiro << endl;
return 0;
}
Se não houver espaço para alocar memória, new retornará NULL (ou 0, se preferir).
Uma regra em C++ é: toda a alocação de memória feita com new, deve ser eliminado com delete. Se a memória não for liberada, esses "resíduos" de memória formarão o chamado "memory leaks". Para embarcados isso é mais significativo, pois devido aos recursos limitados, a memória tenderá a se esgotar prematuramente. Pra piorar, dispositivos embarcados tendem a ficar ligados continuamente, nem dá pra contar com reinicializações programadas.
Seguindo a regra, é simples gerenciar a memória:
int *ponteiro = new int;
//resto do programa...
//...finalizou? Então...
delete ponteiro;
Isso não removerá o ponteiro, mas a memória para qual o ponteiro aponta, sendo possível reutilizá-lo para uma nova alocação com new. Uma vez liberada a memória, o processo delete não deve se repetir. O resultado pode ser qualquer coisa inesperada.
O delete só deve ser utilizado com alocações criadas com new. Isso não funcionará:
int valor = 7;
int *ponteiro = &valor;
delete ponteiro;
Como citei no primeiro artigo, tenho alguns livros de C++, sendo o meu preferido C++ Primer Plus, mas é leitura em inglês. Se inglês não é problema para você, recomendo fortemente. Para consultas rápidas e/ou específicas, uma excelente opção é o site cplusplus, nesse link.
Ainda tem material para mais uns 10 artigos sobre ponteiros. Os escreverei em largos intervalos para que não seja tedioso para vocês nem para mim.
O vídeo demonstrativo em nosso canal está disponível na playlist Programação. Se não é inscrito no canal ainda, inscreva-se, deixe seu like se gostar e comente!
Espero que estejam gostando do conteúdo!
Revisão: Ricardo Amaral de Andrade
Inscreva-se no nosso canal Manual do Maker no YouTube.
Também estamos no Instagram.
Autor do blog "Do bit Ao Byte / Manual do Maker".
Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.