O desenvolvimento de softwares na linguagem de programação C++, um recurso muito utilizado e poderoso dá aos programadores a possibilidade de manipular contextos de memória utilizando ponteiros e referências.

Tal recurso pode agir como uma espada de dois gumes. Se bem utilizado, trará poder de processamento no uso da memória disponível, mas se mal utilizado, poderá trazer consequências desastrosas para a aplicação, ou pior, trazer consequências desastrosas no pós desenvolvimento, no período de implantação do software.

… Sabemos, que o quanto antes capturamos um problema de software, os custos serão menores do que identificar um problema na fase final do projeto, na implantação do sistema.

A manipulação da memória é uma ação que exige atenção e cuidado no desenvolvimento de sistemas, isto faz a diferença entre o sucesso e o fracasso da aplicação, aproveitando ao máximo os recursos disponíveis de hardware e software.

Nesta postagem vamos aprender a criar, manipular e remover da memória os ponteiros e as referências.

Ponteiros

Um ponteiro nada mais é do que uma variável que armazena um endereço de memória.

Mas, o que é a memória ?

A memória do computador ou memória RAM(Random Access Memory), nada mais é do que um espaço físico de armazenamento de dados temporários, de uso do sistemas de computadores. Ela possui setores que armazenam dados, estes que são declarados em uma aplicação como variáveis, ponteiros, referencias e outros recursos do software.

O consumo dos dados na memória, varia de acordo com o seu tipo de dados(int, char, long …), sendo que na declaração de um ponteiro também é declarado o seu tipo, vejamos:


#include
#include

usigng namespace std;

int main(argc, char *argv[]){
unsigned int address_number = 3560;
unsigned int *p_value = &address_number;

cout << *p_value << endl; return 0; }

Repare que no código acima a declaração do ponteiro "p_value" recebe o endereço da variavel "address_number" pelo operador de referência "&", em seguida o valor apontado por "p_value" é apresentado em tela. Repare ainda que a exibição do valor contido na variavel "address_number" é exibido pelo ponteiro "p_value", devemos observar que para exibir o valor apontado por um ponteiro é necessário a utilização do operador "*" antes do nome do ponteiro.

A memória do computador possui endereços que podem variar de arquitetura para arquitetura, conhecimento no qual não é necessário no momento, devemos nos ater apenas que um ponteiro irá armazenar este endereço e que ele pode variar de acordo com a disponibilidade da memória livre.

"... Quando cito a não importância de saber qual o valor do endereço de memória, não levem ao pé da letra, tudo irá depender de sua necessidade. Devo lembrar ainda que este tipo de informação é variável, pois o endereço de memória irá retornar um valor diferente a cada requisição, pois está disponibilidade irá depender da memória livre. ..."

Vejamos abaixo uma demonstração do endereço de memória:


#include
#include

using namespace std;

int main(argc, char *argv[]){
unsigned int address_number = 3560;
unsigned int *p_value = &address_number;

cout << p_value << endl; return 0; }

Operador new

O operador new, aloca memória para a aplicação de acordo com  a disponibilidade da memória livre e a tipagem de dados.

Utilizando o operador "new" a aplicação irá receber um endereço de memória em caso de sucesso, mas se algo der errado a solicitação de alocação de memória irá obter um valor nulo (NULL). Por isso é crucial que a cada pedido de alocação de memória, o desenvolvedor verifique tal disponibilidade para não causar danos a aplicação.

Abaixo vejamos a utilização do operador:


unsigned int *pvalue;
pvalue = new unsigned int;

ou


unsigned int *pvalue = new unsigned int;

Operador delete

O operador delete, devolve a memória alocada pelo operador "new", podendo está ser solicitada novamente, de acordo com as necessidades da aplicação.

Abaixo vejamos a utilização do operador:


unsigned int *pvalue = new unsigned int;
*pvalue = 3572;

delete pvalue;

Uma observação muito importante é que após utilizar o operador delete para um ponteiro, apenas estamos dizendo para o compilador devolver a memória para a área disponivel, mas isto não remove o endereço de memória armazenado pelo ponteiro.

Então, uma boa prática de desenvolvimento seria, após utilizar o operador delete para devolver a memória requisitada, atribuir a constante NULL para o ponteiro.

Se por engano uma segunda chamada ao operador delete for efetuada para desalocar o ponteiro para a memória, está ação resultaria na quebra do sistema. Logo atribuir a constante NULL para o ponteiro desalocado, remove a referência ao endereço de memória existente como seu valor, o que evita o compilador efetuar uma tentativa de desalocação de memória para uma área ja removida da aplicação.

Referências

Uma referência é um nome alternativo(Alias) para uma variável declarada no sistema. Recurso no qual é muito utilizado na passagem de parametros para funções.

A utilização da referência, se dá, com a colocação do operador "&" na declaração da variável, após o tipo de dados e antes da declaração do nome, vejamos:


#include
#include

using namespace std;

int main(int argc, char *argv[]){
unsigned int x = 20;
unsigned int &ref = x;

cout << "valor: " << ref << endl; cout << "Endereço de memória da variavel x: " << &x << endl; cout << "Endereço de memória da variavel p: " << &ref << endl; return 0; }

Reparem que no código acima, a declaração da varial ref possui o "&" (e-comercial) antes do seu nome. Podemos ainda verificar que pref possui o mesmo endereço da variavel referenciada.

Nas postagens seguintes desta série veremos mais sobre os ponteiros e as referências, utilizando-as em funções, objetos e métodos de classes. Recurso impressindivel para uma aplicação em C++.

Introdutório sequencial:

  1. Introdução.
  2. Tipos de Dados em C++.
  3. Variáveis e Constantes em C++
  4. Matriz, Array e Vetor em C++
  5. Ponteiro e Referência em C++
  6. Operadores(Lógicos e Matemáticos)
  7. Estrutura de Controle de Fluxo
  8. Funções
  9. Classes
  10. Herança
  11. Poliformismo
  12. Abstração (virtual)
  13. Tipos Genéricos (templates)
  14. Namespaces
  15. Exceções (try, catch, throw)
  16. Standard Template Library (STL)
  17. Entrada e Saida Padrão (cin, cout, cerr)
  18. Manipulando Arquivos (IO)
  19. Sockets
  20. Bibliotecas padrão C++
  21. Compiladores C++.