operatory delete vs delete [] w C ++

139

Jaka jest różnica między operatorami deletei delete[]w C ++?

shreyasva
źródło
To pytanie może być odpowiednie dla stackoverflow.com/questions/1913343/ ...
ostry
7
Problemy z delete i delete [] są jednym z powodów, dla których lubię inteligentne wskaźniki i używam vector<>zamiast tablicy, kiedy tylko mogę.
David Thornley
@DavidThornley Jeśli używasz inteligentnych wskaźników, nadal musisz znać różnicę w tym sensie, że nadal musisz wiedzieć, aby nie pisać, np. std::unique_ptr<int>(new int[3])Ponieważ wywoła regularne deletena tablicy, co jest niezdefiniowanym zachowaniem. Zamiast tego musisz użyćstd::unique_ptr<int[]>
Arthur Tacca

Odpowiedzi:

160

deleteOperator zwolni pamięć i wywołuje destruktor dla pojedynczego obiektu utworzonego new.

delete []Operator zwolni z pamięcią i żądanie destruktory szeregu obiektów utworzonych new [].

Użycie deletena wskaźniku zwróconym przez new []lub delete []na wskaźniku zwróconym przez newpowoduje niezdefiniowane zachowanie.

Nick Meyer
źródło
3
Zastanawiam się, czy użycie funkcji delete na nowej tablicy [] typów pierwotnych, takich jak int lub char (bez konstruktora / destruktora), również prowadzi do niezdefiniowanego zachowania. Wygląda na to, że rozmiar tablicy nie jest nigdzie przechowywany, gdy używasz typów pierwotnych.
thomiel
21
Jeśli standard nie definiuje tego, co się stanie, kiedy to się stanie, jest to z definicji „niezdefiniowane zachowanie”, nawet jeśli Twój kompilator deterministycznie robi to, co chcesz. Inny kompilator może zrobić coś zupełnie innego.
Rob K
Zrobiłem ten błąd, gdy miałem tablicę ciągów C, takich jak „char ** strArray”. Jeśli masz tablicę, tak jak ja, musisz iterować przez tablicę i usunąć / zwolnić każdy element, a następnie usunąć / zwolnić sam strArray. Używanie "delete []" na tablicy, którą mam, nie działa, ponieważ (jak wskazano w powyższych komentarzach i odpowiedzi), WZYWA DESTRUKTORY, tak naprawdę nie zwalnia każdego gniazda.
Katianie
89

delete[]Operator służy do usuwania tablic. deleteOperator jest używany do usuwania przedmiotów nie tablicy. Wywołuje operator delete[]i operator deletedziała odpowiednio w celu usunięcia pamięci, którą zajmowała tablica lub obiekt niebędący tablicą po (ostatecznie) wywołaniu destruktorów dla elementów tablicy lub obiektu niebędącego tablicą.

Poniżej przedstawiono relacje:

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;

Dla newktóry tworzy tablicę (tak, albo new type[]czy newstosowany do konstrukcji typu macierz), wygląd standard w odniesieniu do operator new[]klasy typu elementu tablicy lub w zasięgu globalnym i przekazuje żądaną ilość pamięci. Może zażądać więcej niż N * sizeof(ElementType)gdyby chciał (na przykład zapisać liczbę elementów, aby później podczas usuwania wiedział, ile wywołań destruktora ma wykonać). Jeśli klasa zadeklaruje, operator new[]że dodatkowy do ilości pamięci akceptuje inny size_t, ten drugi parametr otrzyma liczbę przydzielonych elementów - może go użyć w dowolnym celu (debugowanie itp.).

W przypadku tego, newktóry tworzy obiekt niebędący tablicą, będzie szukał operator neww klasie elementu lub w zasięgu globalnym. Przekazuje żądaną ilość pamięci (dokładnie sizeof(T)zawsze).

W przypadku delete[], sprawdza typ klasy elementów tablic i wywołuje ich destruktory. operator delete[]Funkcja używana jest jeden w klasie typu elementu, albo jeśli nie ma nikogo wtedy w zasięgu globalnym.

W przypadku delete, jeśli przekazany wskaźnik jest klasą bazową rzeczywistego typu obiektu, klasa bazowa musi mieć wirtualny destruktor (w przeciwnym razie zachowanie jest niezdefiniowane). Jeśli nie jest to klasa bazowa, wywoływany jest destruktor tej klasy i używany jest operator deletew tej klasie lub globalnej operator delete. Jeśli przekazano klasę bazową, wywoływany jest destruktor rzeczywistego typu obiektu i operator deleteużywany jest element znaleziony w tej klasie, a jeśli nie ma, operator deletewywoływany jest element globalny . Jeśli operator deleteklasa ma drugi parametr typu size_t, otrzyma liczbę elementów do zwolnienia.

Johannes Schaub - litb
źródło
20

Jest to podstawowe użycie wzorca alokacji / alokacji DE w języku c ++ malloc/ free, new/ delete, new[]/delete[]

Musimy odpowiednio z nich korzystać. Ale chciałbym dodać to szczególne zrozumienie różnicy między deleteidelete[]

1) deletesłuży do usuwania alokacji pamięci przydzielonej dla pojedynczego obiektu

2) delete[]służy do usuwania alokacji pamięci przydzielonej dla tablicy obiektów

class ABC{}

ABC *ptr = new ABC[100]

kiedy mówimy new ABC[100], kompilator może uzyskać informacje o tym, ile obiektów należy zaalokować (tutaj jest to 100) i wywoła konstruktor dla każdego z utworzonych obiektów

ale odpowiednio, jeśli po prostu użyjemy delete ptrw tym przypadku, kompilator nie będzie wiedział, ile obiektów ptrwskazuje i zakończy wywołanie destruktora i usunięcie pamięci tylko dla 1 obiektu (pozostawiając wywołanie destruktorów i cofnięcie alokacji pozostałych 99 obiektów). W związku z tym nastąpi wyciek pamięci.

więc musimy użyć delete [] ptrw tym przypadku.

ravs2627
źródło
3
To powinna być prawidłowa odpowiedź. Żadna z pozostałych odpowiedzi nie wspomina o wyraźnej różnicy: „ale odpowiednio, jeśli użyjemy po prostu delete ptr w tym przypadku, kompilator nie będzie wiedział, na ile obiektów wskazuje ptr i zakończy wywołanie destruktora i usunięcie pamięci tylko dla 1 obiektu”
Don Larynx,
1
Jak osiągamy to samo w C?
Dogus Ural
@DogusUral Dlaczego? W C nie ma destruktorów, więc po prostu free()to i to. Jeśli używasz wzorca pseudo-destruktora, musisz wywołać go raz dla każdego obiektu za pomocą forpętli.
Kotauskas
@DonLarynx poprawna różnica polega na tym, że pomieszanie ich powoduje źle sformułowany program. Implementacja może wiedzieć, ile obiektów ma zniszczyć lub nie . Dozwolone jest, aby wiedzieć, że został nazwany błędem, i przerwać program, informując Cię, gdzie jest problem.
Caleth
6

Operatory deletei delete []są używane odpowiednio do niszczenia obiektów utworzonych za pomocą newi new[], powracając do przydzielonej pamięci pozostałej dostępnej dla menedżera pamięci kompilatora.

Obiekty utworzone za pomocą newmuszą koniecznie zostać zniszczone za pomocą delete, a tablice utworzone za pomocą new[]należy usunąć za pomocą delete[].

san983
źródło
3

Kiedy zadałem to pytanie, moje prawdziwe pytanie brzmiało: „czy jest między nimi różnica? Czy środowisko wykonawcze nie musi przechowywać informacji o rozmiarze tablicy, a więc czy nie będzie w stanie stwierdzić, którą z nich mamy na myśli?” To pytanie nie pojawia się w „pytaniach pokrewnych”, więc aby pomóc takim jak ja, oto odpowiedź na to pytanie: „dlaczego w ogóle potrzebujemy operatora delete []?”

Ekalavya
źródło
Dzięki za powrót i umieszczenie tego.
Ziffusion,
0

deletejest używany dla pojedynczego wskaźnika i delete[]służy do usuwania tablicy za pomocą wskaźnika. To może pomóc ci lepiej zrozumieć.

nishant arora
źródło
-6

Cóż… może myślę, że to jest tylko wyraźne. Rozróżnia się operator deletei operator, delete[]ale deleteoperator może również zwolnić tablicę.

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

I już sprawdziłem ten kod, czy nie ma wycieku pamięci.

Witaj świecie
źródło