operadores delete vs delete [] em C ++

135

Qual é a diferença entre deletee delete[]operadores em C ++?

shreyasva
fonte
Você pode achar esta questão relevante stackoverflow.com/questions/1913343/...
sharptooth
7
Os problemas com delete e delete [] são uma das razões pelas quais eu gosto de ponteiros inteligentes e o uso em vector<>vez de uma matriz sempre que posso.
David Thornley
@DavidThornley Se você estiver usando ponteiros inteligentes, ainda precisará saber a diferença no sentido de que ainda precisa saber para não escrever std::unique_ptr<int>(new int[3]), por exemplo , porque ele chamará regularmente deletea matriz, que é um comportamento indefinido. Em vez disso, você precisa usarstd::unique_ptr<int[]>
Arthur Tacca

Respostas:

150

O deleteoperador desaloca a memória e chama o destruidor para um único objeto criado com new.

O delete []operador desaloca a memória e chama destruidores para uma matriz de objetos criados new [].

O uso deletede um ponteiro retornado por new []ou delete []em um ponteiro retornado newresulta em comportamento indefinido.

Nick Meyer
fonte
3
Gostaria de saber se o uso de delete em uma nova matriz [] de tipos primitivos como int ou char (sem construtor / destruidor) também leva necessariamente a um comportamento indefinido. Parece que o tamanho da matriz não é armazenado em nenhum lugar ao usar tipos primitivos.
Thomiel 6/07
21
Se o padrão não definir o que acontece quando isso é feito, é por definição "comportamento indefinido", mesmo que seu compilador faça de maneira determinística o que você gostaria que ele fizesse. Outro compilador pode fazer algo completamente diferente.
Rob K
Cometi esse erro quando tinha uma matriz de C como "char ** strArray". Se você possui uma matriz como a minha, precisa percorrer a matriz e excluir / liberar cada elemento e excluir / liberar o próprio strArray. O uso de "delete []" na matriz que eu tenho não funciona, pois (como apontado pelos comentários e respostas acima), CHAMA DESTRUTORES, na verdade, não libera cada slot.
Katianie
88

O delete[]operador é usado para excluir matrizes. O deleteoperador é usado para excluir objetos que não são da matriz. Ele chama operator delete[]e operator deletefunciona, respectivamente, para excluir a memória que o objeto da matriz ou não matriz ocupou após (eventualmente) chamar os destruidores dos elementos da matriz ou do objeto que não é da matriz.

O seguinte mostra as relações:

typedef int array_type[1];

// create and destroy a int[1]
array_type *a = new array_type;
delete [] a;

// create and destroy an int
int *b = new int;
delete b;

// create and destroy an int[1]
int *c = new int[1];
delete[] c;

// create and destroy an int[1][2]
int (*d)[2] = new int[1][2];
delete [] d;

Para o newque cria uma matriz (portanto, new type[]ou newaplicada a uma construção de tipo de matriz), o Padrão procura um operator new[]na classe de tipo de elemento da matriz ou no escopo global e passa a quantidade de memória solicitada. Ele pode solicitar mais do N * sizeof(ElementType)que deseja (por exemplo, armazenar o número de elementos, portanto, mais tarde, ao excluir, sabe quantas chamadas de destruidor devem ser feitas). Se a classe declarar operator new[]que um adicional à quantidade de memória aceita outro size_t, esse segundo parâmetro receberá o número de elementos alocados - poderá usá-lo para qualquer finalidade que desejar (depuração, etc ...).

Para o newque cria um objeto que não é de matriz, ele procurará um operator newna classe do elemento ou no escopo global. Passa a quantidade de memória solicitada (exatamente sizeof(T)sempre).

Para o delete[], ele examina o tipo de classe de elemento dos arrays e chama seus destruidores. A operator delete[]função usada é a da classe do tipo de elemento ou, se não houver, no escopo global.

Para o delete, se o ponteiro passado é uma classe base do tipo de objeto real, a classe base deve ter um destruidor virtual (caso contrário, o comportamento é indefinido). Se não for uma classe base, o destruidor dessa classe será chamado e um operator deletenessa classe ou no global operator deleteserá usado. Se uma classe base foi aprovada, o destruidor do tipo de objeto real é chamado e o operator deleteencontrado nessa classe é usado, ou, se não houver, um global operator deleteé chamado. Se o operator deletena classe tiver um segundo parâmetro do tipo size_t, ele receberá o número de elementos a serem desalocados.

Johannes Schaub - litb
fonte
18

Esse é o uso básico do padrão alocar / DE-alocar em c ++ malloc/ free,new / delete, new[]/delete[]

Precisamos usá-los correspondentemente. Mas eu gostaria de acrescentar esse entendimento específico para a diferença entre deleteedelete[]

1) delete é usado para desalocar a memória alocada para um único objeto

2) delete[]é usado para desalocar a memória alocada para a matriz de objetos

class ABC{}

ABC *ptr = new ABC[100]

quando dizemos new ABC[100] , o compilador pode obter as informações sobre quantos objetos precisam ser alocados (aqui é 100) e chamará o construtor para cada um dos objetos criados

mas correspondentemente se simplesmente usarmos delete ptr nesse caso, o compilador não saberá quantos objetos ptrestão apontando e acabará chamando o destruidor e excluindo a memória para apenas 1 objeto (deixando a invocação de destruidores e desalocação dos 99 objetos restantes). Portanto, haverá um vazamento de memória.

então precisamos usar delete [] ptrneste caso.

ravs2627
fonte
3
Essa deve ser a resposta correta. Nenhuma das outras respostas menciona a diferença distinta: "mas correspondentemente, se simplesmente usarmos delete ptr para esse caso, o compilador não saberá quantos objetos esse ptr está apontando e acabará chamando o destruidor e excluindo a memória para apenas 1 objeto"
Don Laringe
1
Como conseguimos a mesma coisa em C?
31717 Dogus Ural
@DogusUral Why? Não há destruidores em C, então você apenas free()isso e aquilo. Se você usar um padrão pseudo-destruidor, precisará chamá-lo uma vez para cada objeto usando um forloop.
Kotauskas 13/10/19
@DonLarynx a diferença correta é que misturá-los resulta em um programa mal formado. Uma implementação pode saber quantos objetos devem ser destruídos ou não . É permitido saber que foi chamado de errado e abortar o programa, informando onde está o problema.
Caleth
6

Os operadores deletee delete []são usados ​​respectivamente para destruir os objetos criados com newenew[] , retornando à memória alocada deixada disponível para o gerenciador de memória do compilador.

Os objetos criados com newdevem necessariamente ser destruídos com deletee as matrizes criadas com new[]devem ser excluídas com delete[].

san983
fonte
2

Quando eu fiz essa pergunta, minha verdadeira pergunta era: "existe uma diferença entre os dois? O tempo de execução não precisa manter informações sobre o tamanho da matriz e, portanto, não será capaz de dizer qual deles queremos dizer?" Esta pergunta não aparece em "perguntas relacionadas"; portanto, apenas para ajudar pessoas como eu, aqui está a resposta: "por que precisamos do operador delete []?"

Ekalavya
fonte
Obrigado por voltar e colocar isso.
Ziffusion
0

deleteé usado para um único ponteiro e delete[]é usado para excluir uma matriz por meio de um ponteiro. Isso pode ajudá-lo a entender melhor.

aris nishant
fonte
-6

Bem ... talvez eu pense que é apenas por explícito. O operador deletee o operador delete[]se distinguem, mas o deleteoperador também pode liberar a matriz.

test* a = new test[100];
delete a;

E já verifiquei esse código não tem vazamento de memória.

Olá Mundo
fonte