Não crie arrays com new em C++! Entenda o porquê com 3 razões

Containers representando os containers em C++ no contexto de se criar um array com new em C++.

Para aqueles que acham que criar um array com new em C++ é muita dor de cabeça, vale a pena lembrar que poderia ser pior: aqueles que já programaram em C devem estar acostumados a criar arrays “na mão” com malloc() e afins. Eles também devem saber que esse procedimento não é dos mais claros e dos mais protegidos contra falhas humanas (era muito fácil alocar a quantidade errada de memória para o seu array). Felizmente, no C++ as coisas se tornaram um pouco mais fáceis com a introdução da palavra-chave new (apesar dela ter seus problemas, como veremos a seguir).

Como criar um array usando new?

Para se criar um array usando new em C++, é preciso primeiro se ter um ponteiro para o tipo de dado que será armazenado no array, e em seguida é preciso usar a seguinte sintaxe: ptr = new tipo-do-dado[tamanho-do-array]; , onde ptr é o nome da nossa variável ponteiro (int* ptr;), tipo-do-dado pode ser um tipo padrão da linguagem (int, double etc.) ou um tipo criado pelo usuário (como uma classe ou um struct), e tamanho-do-array é a quantidade de elementos que serão armazenados no array. Veja abaixo um exemplo de uso de new para se alocar um array em C++.

/* Como criar um array usando new em C++ 
*  Exemplo #1 - array criado com new
*/

#include <iostream>
using namespace std;

int main() {
    int* intPtr;
    intPtr = new int[3]; // Os valores em intPtr não foram inicializados

    for (size_t idx = 0; idx < 3; ++idx) {
        intPtr[idx] = 0;
        cout << "Valor do elemento: " << intPtr[idx] << endl;
    }

    delete intPtr;

    return 0;
}
texto "Valor do elemento: 0" repetido três vezes para o exemplo de se criar um array com new em C++.
Figura 1 – Resultado da execução do código do exemplo 1 usando array criado com new.

Por que não usar new para criar um array em C++? 3 principais razões

Stop! Não crie arrays com new em C++
Não crie arrays com new em C++!

Há três principais razões para que não se use new para a criação de arrays em C++:

Razão #1 – É preciso liberar a memória manualmente usando delete

É necessário lembrar-se de liberar a memória alocada com new usando delete, o que torna-se complicado em programas grandes. Se isso não for feito, a memória permanecerá alocada até o fim da execução do programa, resultando em um vazamento de memória.

Razão #2 – O tamanho do array criado com new é fixo

Não é possível aumentar o tamanho do array criado com new dinamicamente (durante a execução do programa). Para alocar mais elementos do que a quantidade inicialmente alocada, é preciso deletar o array com delete e então realocar mais memória com outro new.

Razão #3 – não é possível usar as formas mais recentes do laço for

Como podemos ver no exemplo anterior, fui obrigado a utilizar a forma do laço for que usa índices para acessar os elementos do vetor, ao invés das formas introduzidas com os novos padrões (o for com iteradores e o range-based  for).

Qual alternativa usar ao invés de criar um array com new em C++?

Já que usar o new para se criar arrays em C++ não é a melhor opção, o que podemos usar para criar arrays de outro modo?

Alternativa #1 – std::vector

Ao invés de criar um array na mão, usando new, é melhor utilizar o container vector da biblioteca padrão std. O vector tem a vantagem de se comportar do mesmo modo que um array alocado com new (é possível percorrê-lo da mesma forma, e realizar a maioria das operações de igual modo), além de aumentar e diminuir seu tamanho automaticamente, e gerenciar sua própria memória: o usuário não precisa se preocupar em deletar a memória usada pelo vetor depois da sua utilização, pois isso é feito automaticamente pelo programa.

Para se criar um array usando vector, a sintaxe utilizada é a seguinte: std::vector<tipo-dos-dados> nome-da-variavel(tamanho-do-vetor, valor-inicial-dos-elementos). Há outras formas de se incializar um vetor, caso o leitor esteja curioso, como o uso de listas de inicializacão, mas tratarei delas em um outro artigo.

Veja a seguir o mesmo código do exemplo 1, mas desta vez usando vector.

/* Como criar um array usando new em C++ 
*  Exemplo #2 - vector
*/

#include <iostream>
#include <vector>

using namespace std;

int main() {
    // Estou usando a forma std::vector para
    // deixar claro que vector é um container da biblioteca padrão (a std).

    std::vector<int> intPtr(3, 0); // vetor de 3 elementos inteiros, todos com valor 0
    // Posso adicionar mais elementos ao vetor.
    intPtr.push_back(23);
    intPtr.push_back(8);
    for (const auto& intValue : intPtr) {
        cout << "Valor do elemento: " << intValue << endl;
    }

    // Não é preciso deletar a memória após sua utilização

    return 0;
}
texto "Valor do elemento: 0" repetido três vezes e mais duas vezes, mas com os valores 23 e 8 ao fim, para o exemplo de se criar um array em C++ usando vector.
Figura 2 – Resultado da execução do código do exemplo 2 usando vector da biblioteca padrão.

Alternativa #2 – std::array

A segunda alternativa aos arrays criados usando new em C++ são os arrays da biblioteca padrão: o container array declarado no cabeçalo (header) de mesmo nome (#include <array>). Os arrays da biblioteca padrão são a forma que os modelos recentes do C++ encontraram de se criar um array como aquele à moda antiga (usando ponteiros e new), mas com as vantagens dos containers da “nova geração”.

O objeto de tipo array tem tamanho fixo (ao contrário do vector), mas tem duas vantagens em relação ao array alocado manualmente com new:

  1. Não é preciso liberar a memória dos objetos de tipo array manualmente após o seu uso;
  2. É possível usar as formas mais sofisticadas dos laços for para percorrer containers de tipo array.

Para declarar um array, as duas sintaxes principais – e equivalentes – são as seguintes:

  1. std::array<tipo-do-dado, tamanho-do-array> nome-da-variavel = {primeiro-elemento, segundo-elemento, ..., ultimo-elemento}
  2. std::array<tipo-do-dado, tamanho-do-array> nome-da-variavel {primeiro-elemento, segundo-elemento, ..., ultimo-elemento}

O tipo-do-dado é o tipo dos objetos armazenados no array (int, double, string etc.); o tamanho-do-array é a quantidade de elementos que serão armazenados no container; nome-da-variavel é o nome do array que será criado, e os elementos dentro das chaves ({ }) são os elementos que serão armazenados no array.

Vejamos o nosso exemplo de base reescrito para utilizar os arrays da biblioteca padrão.

/* Como criar um array usando new em C++ 
*  Exemplo #3 - array da biblioteca padrão
*/

#include <iostream>
#include <array>

using namespace std;

int main() {
    // Estou usando a forma std::array para
    // deixar claro que array é um container da biblioteca padrão (a std).

    std::array<int, 3> intArray{10, 20, 30}; // Array com 3 elementos: 10, 20 e 30.
    for (const auto& intValue : intArray) {
        cout << "Valor do elemento do array: " << intValue << endl;
    }

    // Não é preciso deletar a memória após sua utilização

    return 0;
}
Figura 3 - Resultado da execução do código do exemplo 3 para se criar um array com new em C++. 3 linhas com a string:"Valor do elemento:" seguido dos valores 10, 20 e 30.
Figura 3 – Resultado da execução do código do exemplo 3 usando arrays da biblioteca padrão.

Conclusão

Neste artigo vimos como é possível se criar um array usando new em C++ e também vimos 3 razões para não fazê-lo, que são as seguintes: 1) é preciso liberar a memória manualmente usando delete; 2) o tamanho do array criado com new em C++ é fixo; 3) não é possível usar as formas mais recentes do laço for. Além disso, vimos também duas alternativas para os arrays criados com new em C++: os containers vector e array da biblioteca padrão std.

Foto de perfil de Emanoel

Sou apaixonado por tecnologia, literatura e também filosofia. O cultivo dessas paixões ao longo da minha trajetória me inspiraram a compartilhar aquilo que aprendo com os outros da maneira mais clara que eu possa. Sou formado em Engenharia Elétrica no Brasil, e também sou engenheiro formado na França. Trabalho atualmente como programador C++ em uma multinacional francesa, uma das maiores empresas de TI do mundo.

Leave a Reply

Your email address will not be published. Required fields are marked *