Powodem tego wymogu jest historia, a ponieważ new type
i new type [size]
zwracają różne rzeczy, które wymagają innego sprzątania.
rozważyć ten kod
Foo* oneEntry = new Foo;
Foo* tenEntries = new Foo[10];
Są zarówno zwrócić Foo * wskaźnik, różnica jest drugie połączenie spowoduje konstruktora Foo miano 10x i 10x nie jest grubsza tyle pamięci.
Teraz chcesz uwolnić swoje obiekty.
Dla pojedynczego obiektu można nazwać usuwanie - np. delete oneEntry
. To wywołuje destruktor obiektów i zwalnia pamięć.
Ale tu jest problem - oneEntry i tenEntries są po prostu wskaźnikami Foo. Kompilator nie ma pojęcia, czy wskazują na jeden, dziesięć, czy tysiąc elementów.
Podczas korzystania ze specjalnej składni delete []
.Mówi to kompilatorowi: "to jest tablica obiektów, oblicz liczbę, a następnie zniszcz wszystkie".
To, co naprawdę się dzieje, to, że kompilator przechowuje w tajemnicy "rozmiar" gdzie indziej. Kiedy wywołasz delete [], wie, że ta sekretna wartość istnieje, więc może dowiedzieć się, ile obiektów znajduje się w tym bloku pamięci i je zniszczyć.
Pytanie, które można następnie zadać, brzmi: "dlaczego kompilator nie zawsze przechowuje rozmiar?"
To świetne pytanie i pochodzi z początków C++. Istniało pragnienie, aby dla wbudowanych typów (char, int, float, itp.) Następujące byłyby ważne dla C++;
int* ptr = new int;
free(ptr);
int* ptr = (int*)malloc(sizeof(int) * someSize);
delete ptr;
Rozumowanie to było oczekiwanie, że ludzie dostarczają bibliotek, które zwróciło się dynamicznie przydzielone pamięci, a użytkownicy tych bibliotek miałyby żadnego sposobu dowiedzenia się, czy używać za darmo/usunąć.
Ta potrzeba kompatybilności oznaczała, że rozmiar tablicy nie mógł być przechowywany jako część samej tablicy i musiał być przechowywany w innym miejscu. Z tego powodu (i pamiętajcie, że było to na początku lat 80.) zdecydowano, że będzie to książka zawierająca tylko tablice, a nie pojedyncze elementy. W związku z tym tablice wymagają specjalnej składni delete, która wyszukuje tę wartość.
Powodem, dla którego malloc/free nie ma tego problemu jest to, że po prostu zajmują się blokami pamięci i nie muszą się martwić o wywołanie konstruktorów/destruktorów.
Być może możesz dodać do odpowiedzi informacje/linki dotyczące nadpisania różnych nowych/usunąć, aby odpowiedzieć na późniejsze pytanie. –
@Brian Z ciekawości: dlaczego potrzeba rozróżnienia między tymi dwoma? W jaki sposób, na początku, istnieje delete []? – FreeMemory