Eu me deparei com um questionário que envolvia declaração de matriz com tamanhos diferentes. A primeira coisa que me veio à mente é que eu precisaria usar a alocação dinâmica com o new
comando, assim:
while(T--) {
int N;
cin >> N;
int *array = new int[N];
// Do something with 'array'
delete[] array;
}
No entanto, vi que uma das soluções permitia o seguinte caso:
while(T--) {
int N;
cin >> N;
int array[N];
// Do something with 'array'
}
Depois de um pouco de pesquisa, li que o g ++ permite isso, mas ele me fez pensar: em quais casos é necessário usar a alocação dinâmica? Ou será que o compilador traduz isso como alocação dinâmica?
A função de exclusão está incluída. Observe, no entanto, que a pergunta aqui não é sobre vazamentos de memória.
c++
arrays
dynamic-memory-allocation
static-memory-allocation
learning_dude
fonte
fonte
std::vector
(std::vector<int> array(N);
).new OBJ
diretamente.Respostas:
Nenhum trecho que você mostra é um código C ++ moderno e idiomático.
new
edelete
(enew[]
edelete[]
) não são preteridos no C ++ e nunca serão. Eles ainda são o caminho para instanciar objetos alocados dinamicamente. No entanto, como você sempre deve combinar anew
com adelete
(e anew[]
com adelete[]
), é melhor mantê-las nas classes (biblioteca) que garantem isso para você. Consulte Por que os programadores de C ++ devem minimizar o uso de 'new'? .Seu primeiro trecho usa um "nu"
new[]
e nuncadelete[]
é a matriz criada. Isso é um problema.std::vector
faz tudo o que você precisa aqui muito bem. Ele usará alguma forma denew
bastidores (não vou me aprofundar nos detalhes da implementação), mas, para todos os que você precisa saber, é uma matriz dinâmica, mas melhor e mais segura.Seu segundo snippet usa "VLAs (Variable Length Arrays)", um recurso C que alguns compiladores também permitem no C ++ como uma extensão. Diferentemente
new
, os VLAs são essencialmente alocados na pilha (um recurso muito limitado). Mais importante, porém, eles não são um recurso padrão do C ++ e devem ser evitados porque não são portáteis. Eles certamente não substituem a alocação dinâmica (ou seja, heap).fonte
Qt
, pois todas as classes base têm coletores de lixo, então você o usanew
e esquece, na maioria das vezes. Para elementos da GUI, quando o widget pai é fechado, os filhos ficam fora do escopo e são coletados como lixo automaticamente.new
ainda tem uma correspondênciadelete
; é que osdelete
s são feitos pelo widget pai, e não no mesmo bloco de código que osnew
s.Bem, para iniciantes,
new
/delete
não está sendo preterido.No seu caso específico, eles não são a única solução. O que você escolhe depende do que ficou oculto no seu comentário "faça algo com a matriz".
Seu segundo exemplo usa uma extensão VLA não padrão que tenta ajustar a matriz na pilha. Isso tem certas limitações - ou seja, tamanho limitado e a incapacidade de usar essa memória depois que a matriz sai do escopo. Você não pode movê-lo, ele "desaparecerá" depois que a pilha se desfazer.
Portanto, se seu único objetivo é fazer uma computação local e depois jogar os dados fora, pode realmente funcionar bem. No entanto, uma abordagem mais robusta seria alocar a memória dinamicamente, de preferência com
std::vector
. Dessa forma, você tem a capacidade de criar espaço para exatamente quantos elementos precisar, com base em um valor de tempo de execução (que é o que estamos fazendo o tempo todo), mas ele também se limpa muito bem, e você pode movê-lo deste escopo se você quiser manter a memória em uso para mais tarde.Circulando de volta ao começo,
vector
vai provavelmente usarnew
algumas camadas mais profundas, mas você não deve se preocupar com isso, como a interface que apresenta é muito superior. Nesse sentido, usarnew
edelete
pode ser considerado desencorajado.fonte
new
edelete
, em vez disso, usar ponteiros inteligentes comostd::unique_pointer
.std::unique_ptr
std::unique_ptr
chama o destruidor padrãodelete
oudelete[]
, o que significa que o objeto de propriedade deve ter sido alocado por,new
ou pelo menosnew[]
, quais chamadas estão ocultasstd::make_unique
desde o C ++ 14.Seus segundos exemplos usam VLAs ( Arrays de Comprimento Variável), que são realmente um recurso C99 ( não C ++!), Mas, no entanto, são suportados pelo g ++ .
Veja também esta resposta .
Observe que as matrizes de comprimento variável são diferentes de
new
/delete
e não as "preterem" de forma alguma.Esteja ciente de que os VLAs não são ISO C ++.
fonte
O C ++ moderno fornece maneiras mais fáceis de trabalhar com alocações dinâmicas. Os ponteiros inteligentes podem cuidar da limpeza após exceções (que podem ocorrer em qualquer lugar, se permitido) e retornos antecipados, assim que as estruturas de dados referenciadas ficarem fora do escopo, portanto, faça sentido usá-las:
No C ++ 14, você também pode escrever
isso parece ainda melhor e evitaria o vazamento de memória se a alocação falhar. No C ++ 20, você deve conseguir fazer o máximo
isso para mim ainda não é compilado no momento da escrita com o gcc 7.4.0. Nestes dois exemplos, também usamos em
auto
vez de declaração de tipo à esquerda. Em todos os casos, use array como de costume:Vazamentos de memória
new
e falhas de duplicaçãodelete
são algo em que o C ++ é destruído por muitos anos, sendo o "ponto central" da argumentação para mudar para outras linguagens. Talvez seja melhor evitar.fonte
unique/shared_ptr
construtores a favormake_unique/shared
, não apenas não precisa escrever o tipo construído duas vezes (usandoauto
), mas também não corre o risco de perder memória ou recursos se a construção falhar parcialmente (se você estiver usando um tipo que pode falhar)make_shared<int[]>
muito, quando você quase sempre quervector<int>
, mas é bom saber.unique_ptr
IIRC, o construtor, não é apresentado, portanto, paraT
isso, não há risco de vazamentosunique_ptr(new int[size])
eshared_ptr
tem o seguinte: "Se uma exceção for lançada, a exclusão p será chamada quando T não for um tipo de matriz, delete [ ] p caso contrário. ", para que você tenha o mesmo efeito - o risco é paraunique/shared_ptr(new MyPossiblyAllocatingType[size])
.new e delete não estão sendo preteridos.
Os objetos criados pelo novo operador podem ser passados por referência. Os objetos podem ser excluídos usando delete.
new e delete são os aspectos fundamentais do idioma. A persistência de um objeto pode ser gerenciada usando new e delete. Definitivamente, essas não serão depreciadas.
A instrução array int [N] é uma maneira de definir um array. A matriz pode ser usada dentro do escopo do bloco de código anexo. Não pode ser passado como um objeto é passado para outra função.
fonte
O primeiro exemplo precisa de um
delete[]
no final, ou você terá um vazamento de memória.O segundo exemplo usa o comprimento variável da matriz que não é suportado pelo C ++; que só permite constante-expressão de comprimento da matriz .
Nesse caso, é útil usar
std::vector<>
como solução; que agrupa todas as ações que você pode executar em uma matriz em uma classe de modelo.fonte
A sintaxe se parece com C ++, mas o idioma é semelhante ao Algol60 antigo. Era comum ter blocos de código como este:
O exemplo pode ser escrito como:
Às vezes sinto falta disso nos idiomas atuais;)
fonte