Usar malloc vs new Alocadores em C++

Jinku Hu 12 outubro 2023
  1. Utilizar o operador new para alocar memória dinâmica em C++
  2. Utilize o operador new e std::unique_ptr para alocar memória dinâmica em C++
  3. Utilizar a função malloc e realloc/reallocarray para alocar a memória dinâmica
Usar malloc vs new Alocadores em C++

Este artigo explicará vários métodos de utilização de alocadores malloc vs new em C++.

Utilizar o operador new para alocar memória dinâmica em C++

O new é a interface preferida para gerir directamente a memória dinâmica em C++. Constrói um objecto do tipo dado e devolve-lhe o ponteiro. Os objectos atribuídos utilizando o operador new são inicializados por defeito, o que significa que os objectos de tipo embutido e composto têm valores de lixo que precisam de ser inicializados antes de serem utilizados.

Note-se que o new pode ser chamado com múltiplas notações para atender a diferentes necessidades, mas no exemplo seguinte, atribuímos o array int de tamanho 10. Assim, o ponteiro devolvido armazenado na variável arr1 aponta para o pedaço de memória que é de 40 bytes. A função initPrintIntVector só é implementada para demonstrar melhor um exemplo prático de codificação. Uma vez que estamos a utilizar o chamado ponteiro nu, é importante libertar a memória alocada com o operador delete antes que o programa saia. No entanto, parênteses após a delete são também necessários para desalocar cada local do array.

#include <iomanip>
#include <iostream>
#include <random>
#include <vector>

using std::cout;
using std::endl;
using std::setw;
using std::vector;

constexpr int SIZE = 10;
constexpr int NEW_SIZE = 20;
constexpr int MIN = 1;
constexpr int MAX = 1000;

void initPrintIntVector(int *arr, const int &size) {
  std::random_device rd;
  std::default_random_engine eng(rd());
  std::uniform_int_distribution<int> distr(MIN, MAX);

  for (int i = 0; i < size; ++i) {
    arr[i] = distr(eng) % 1000;
    cout << setw(2) << arr[i] << "; ";
  }
  cout << endl;
}

int main() {
  int *arr1 = new int[SIZE];

  initPrintIntVector(arr1, SIZE);

  delete[] arr1;
  return EXIT_SUCCESS;
}

Saída (*random):

 8; 380; 519; 536; 408; 666; 382; 244; 448; 165;

Utilize o operador new e std::unique_ptr para alocar memória dinâmica em C++

Embora o new operador pareça ser uma boa ferramenta para a alocação dinâmica de memória, pode ficar bastante sujeito a erros nas grandes bases de código com manipulações intensivas de memória. Nomeadamente, a desalocação dos recursos de memória no momento certo é um problema bastante difícil de resolver, e na sua maioria resulta em fugas de memória ou erros inesperados de tempo de execução. É por isso que a biblioteca padrão, uma vez que a versão C++ 11 acrescentou apontadores inteligentes que apagam automaticamente a memória para a qual apontam. std::unique_ptr é um tipo de apontadores inteligentes, que apenas se permite apontar para o objecto em questão. Note-se que a atribuição ainda é feita utilizando o operador new, e depois de o ponteiro ter sido utilizado podemos sair do programa sem chamar para delete.

#include <iomanip>
#include <iostream>
#include <random>
#include <vector>

using std::cout;
using std::endl;
using std::setw;
using std::vector;

constexpr int SIZE = 10;
constexpr int NEW_SIZE = 20;
constexpr int MIN = 1;
constexpr int MAX = 1000;

void initPrintIntVector(int *arr, const int &size) {
  std::random_device rd;
  std::default_random_engine eng(rd());
  std::uniform_int_distribution<int> distr(MIN, MAX);

  for (int i = 0; i < size; ++i) {
    arr[i] = distr(eng) % 1000;
    cout << setw(2) << arr[i] << "; ";
  }
  cout << endl;
}

int main() {
  std::unique_ptr<int[]> arr2(new int[SIZE]);

  initPrintIntVector(arr2.get(), SIZE);

  return EXIT_SUCCESS;
}

Resultado:

985; 885; 622; 899; 616; 882; 117; 121; 354; 918;

Utilizar a função malloc e realloc/reallocarray para alocar a memória dinâmica

Por outro lado, o código C++ pode chamar a função original de alocação ao estilo C - malloc, que é uma forma bastante arcaica de manipulação dinâmica da memória para os padrões C++ modernos. Não é a forma recomendada de alocar objectos na pilha, mas no lado positivo, o malloc proporciona uma funcionalidade mais flexível.

O malloc é chamado com um único argumento que especifica o sizeof objecto e devolve o void* que deve ser lançado ao tipo correspondente em C++. A única vantagem da memória atribuída ao malloc é que pode ser expandida/encolhida pela função realloc ou reallocarray. A função “realocar” leva o ponteiro ao objecto e o novo tamanho como argumentos, enquanto que a função realocarray leva o ponteiro, o número de elementos, e o tamanho de cada elemento. Note-se que se a memória do objecto for expandida, os antigos valores armazenados permanecem intactos, e os novos elementos adicionados são não inicializados. Assim, o exemplo seguinte imprime os elementos expandidos arr3 apenas para fins de demonstração, e não deve ser o caso no programa do mundo real.

#include <iomanip>
#include <iostream>
#include <random>
#include <vector>

using std::cout;
using std::endl;
using std::setw;
using std::vector;

constexpr int SIZE = 10;
constexpr int NEW_SIZE = 20;
constexpr int MIN = 1;
constexpr int MAX = 1000;

void initPrintIntVector(int *arr, const int &size) {
  std::random_device rd;
  std::default_random_engine eng(rd());
  std::uniform_int_distribution<int> distr(MIN, MAX);

  for (int i = 0; i < size; ++i) {
    arr[i] = distr(eng) % 1000;
    cout << setw(2) << arr[i] << "; ";
  }
  cout << endl;
}

void printIntVector(int *arr, const int &size) {
  for (int i = 0; i < size; ++i) {
    cout << setw(2) << arr[i] << "; ";
  }
  cout << endl;
}

int main() {
  int *arr3 = static_cast<int *>(malloc(SIZE * sizeof(int)));
  //    int *arr3 = static_cast<int *>(malloc(SIZE * sizeof *arr3));
  //    int *arr3 = static_cast<int *>(malloc(sizeof(int[SIZE])));

  initPrintIntVector(arr3, SIZE);

  arr3 = static_cast<int *>(reallocarray(arr3, NEW_SIZE, sizeof(int)));
  // arr3 = static_cast<int *>(realloc(arr3, NEW_SIZE * sizeof(int)));
  printIntVector(arr3, NEW_SIZE);

  free(arr3);
  return EXIT_SUCCESS;
}

Resultado:

128; 346; 823; 134; 523; 487; 370; 584; 730; 268;
128; 346; 823; 134; 523; 487; 370; 584; 730; 268;  0;  0;  0;  0;  0;  0;  0;  0;  0;  0;
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Artigo relacionado - C++ Memory