Teoretycznie mogę to powiedzieć
free(ptr);
free(ptr);
to uszkodzenie pamięci, ponieważ zwalniamy pamięć, która została już zwolniona.
Ale co gdyby
free(ptr);
ptr=NULL;
free(ptr);
Ponieważ system operacyjny będzie zachowywał się w nieokreślony sposób, nie mogę uzyskać faktycznej teoretycznej analizy tego, co się dzieje. Cokolwiek robię, czy to uszkodzenie pamięci, czy nie?
Czy zwolnienie wskaźnika NULL jest prawidłowe?
delete NULL
nie działa w C ++. delete można zastosować do wartości wskaźnika null określonego typu, ale nie doNULL
.delete (int*) NULL
jest legalne, ale niedelete NULL
.ptr
wskazuje na pamięć, a ty jej nie wywołaszfree
, to pamięć wycieknie. Ustawienie goNULL
tak, aby po prostu utraciło dostęp do pamięci i przecieki. Jeśliptr
tak się stanieNULL
, wywołaniefree
jest bez operacji.free(ptr)
zptr = NULL
. Nikt nic takiego nie powiedział.Odpowiedzi:
Zobacz ISO-IEC 9899 .
Biorąc to pod uwagę, patrząc na różne bazy kodów na wolności, zauważysz, że ludzie czasami robią:
Dzieje się tak, ponieważ niektóre środowiska wykonawcze C (na pewno pamiętam, że miało to miejsce na PalmOS) ulegały awarii podczas zwalniania
NULL
wskaźnika.Ale obecnie uważam, że można bezpiecznie założyć, że
free(NULL)
jest to nop zgodnie z instrukcją zawartą w normie.źródło
free(ptr)
gdzieptr
jest zero, nie ma skutków ubocznych. Ale w każdym razie każda pamięć przydzielona przy użyciumalloc()
lubcalloc()
musi zostać zwolniona później za pomocąfree()
free(NULL)
, testując wskaźnikNULL
przed wezwaniemfree()
Wszystkie zgodne ze standardami wersje biblioteki C traktują darmową (NULL) jako no-op.
To powiedziawszy, kiedyś istniało kilka wersji darmowych, które ulegały awarii na darmowym (NULL), dlatego możesz zobaczyć niektóre obronne techniki programowania:
źródło
mówi dokumentacja.
źródło
Pamiętam, jak pracowałem na PalmOS, gdzie się
free(NULL)
zawiesił.źródło
NULL
była jedną z największych różnic w działaniu zestawu narzędzi Palm w porównaniu ze standardową biblioteką.Możesz bezpiecznie usunąć wskaźnik NULL. W takim przypadku żadna operacja nie zostanie wykonana, innymi słowy free () nie robi nic na wskaźniku NULL.
źródło
Zalecane użycie:
Widzieć:
Jeśli ustawisz wskaźnik na
NULL
afterfree()
, możeszfree()
go ponownie wywołać i żadna operacja nie zostanie wykonana.źródło
free(NULL)
jest całkowicie legalny w C, jak równieżdelete (void *)0
idelete[] (void *)0
jest legalny w C ++.Przy okazji, dwukrotne zwolnienie pamięci zwykle powoduje jakiś błąd w czasie wykonywania, więc niczego nie psuje.
źródło
delete 0
nie jest legalne w C ++.delete
jawnie wymaga wyrażenia typu wskaźnika. Dozwolone jest stosowaniedelete
do wpisanej wartości wskaźnika null, ale nie do0
(i nie doNULL
).void*
: P Które destruktory ma działać?void *
tak długo, jak jest to null pointer.buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1);
- tutaj, jeśli masz pecha, buf2 ma dokładnie ten sam adres, co buf1 i przypadkowo zwolniłeś buf1 dwa razy, więc na drugim miejscu wolnym od buf1 faktycznie zwolniłeś buf2 po cichu, bez casuowania jakikolwiek (natychmiastowy) błąd / awaria / cokolwiek. (ale prawdopodobnie nadal będziesz mieć awarię następnym razem, gdy spróbujesz użyć buf2 - a ten scenariusz jest bardzo mało prawdopodobny, jeśli używasz ASLR)free(ptr)
jest zapisany w C, jeśliptr
jestNULL
, jednak większość ludzi nie wie, żeNULL
nie musi być równa 0. Mam ładny, oldschoolowy przykład: na C64, pod adresem 0, znajduje się port IO. Jeśli napisałeś program w C, który uzyskuje dostęp do tego portu, potrzebujesz wskaźnika o wartości 0. Odpowiednia biblioteka C musiałaby rozróżniać od 0 do tego portuNULL
.Z poważaniem.
źródło
nie uszkodzenie pamięci, ale zachowanie zależy od implementacji. Standardowo powinien to być kod prawny.
źródło
ptr wskazuje na jakąś lokalizację w pamięci, powiedzmy 0x100.
Kiedy zwalniasz (ptr), w zasadzie pozwalasz, aby 0x100 był używany przez menedżera pamięci do innych działań lub procesów, a mówiąc prosto, jest to zwolnienie zasobów.
Kiedy robisz ptr = NULL, ustawiasz ptr na nową lokalizację (nie martwmy się tym, czym jest NULL). W ten sposób straciłeś kontrolę nad danymi pamięci 0x100. To właśnie jest wyciek pamięci.
Dlatego nie jest zalecane używanie ptr = NULL na prawidłowym ptr.
Zamiast tego możesz przeprowadzić bezpieczną kontrolę, używając:
if (ptr! = NULL) {free (ptr);}
Kiedy zwolnisz (ptr), gdzie ptr już wskazuje na NULL, nie wykonuje żadnej operacji, więc jest to bezpieczne.
źródło