2017-11-04 93 views
9

Moje pytanie dotyczy usunięcia tablicy z pamięci sterty. Przeczytałem książkę i inne zasoby i inne zasoby like this one, i wszystkie z nich powiedziały, że do usunięcia tablicy z sterty musimy użyć funkcji [] po delete, więc jeśli piszemy nasze kody bez użycia [], to mamy wyciekłą pamięć.usuwanie tablicy ze sterty

na przykład, należy rozważyć poniżej programu

int *s = new int[10]; 
delete [] s; 

Przetestowałem ten mały program w Linuksie za pomocą pakietu valgrind (ten pakiet mógł sprawdzić ile pamięci produkuje wyciekły przez złego kodowania) .Poprzez poniżej komendy w systemie Linux widzieliśmy, że wszystko jest w porządku

sudo valgrind --leak-check=full ./<path_to_exe_file> 

Oto wynik polecenia Linux

==4565== HEAP SUMMARY: 
==4565==  in use at exit: 0 bytes in 0 blocks 
==4565== total heap usage: 1 allocs, 1 frees, 40 bytes allocated 
==4565== 
==4565== All heap blocks were freed -- no leaks are possible 

Ale moje pytanie pojawiło się, gdy próbuję użyć delete bez korzystania z [] i kiedy sprawdzam wyjście valgrind widziałem, że cała pamięć sterty została zwolniona, więc czy to jest poprawne? lub valgrind nie wiedziałem, że cała stertka nie została uwolniona i jakaś część tablicy wciąż jest w środku !! ?? a jeśli valgrind nie może wykryć tego rodzaju wyciekanej pamięci, to istnieje pakiet, który może to wykryć.

+0

'int * s = nowy int [10]; delete s; 'podaje niezdefiniowane zachowanie. Forma operatora 'delete' musi pasować do formy operatora' nowy'. Jedna z możliwych manifestacji niezdefiniowanego zachowania działa zgodnie z oczekiwaniami, takimi jak widzisz. Z innym kompilatorem może działać inaczej lub wcale. – Peter

+0

"usuń" to, co "nowe" i "usuń []", co "nowe" [-ed]. Albo lepiej użyj zamiast tego inteligentnych wskaźników. – Ron

+1

Zastąp 'int' przez' std :: vector 'lub' std :: string', aby zobaczyć oczekiwany wyciek w twoim programie UB. – Jarod42

Odpowiedz

5

Wywołanie delete na tablicy bez użycia [] powoduje niezdefiniowane zachowanie. Niezdefiniowane zachowanie może polegać na tym, że tablica jest poprawnie usunięta, co wydaje się być tym, co zaobserwowałeś. Nie można jednak na tym polegać.

+0

Więc odpowiedź na moje pytanie, dziękuję za wpis, a inne komentarze mówią, że tam jest wyciekła pamięć, ale 'valgrind' nie mógł tego wykryć :) –

+2

Nie, nie ma wycieków pamięć - po prostu masz szczęście. –

+0

Wow Nie wiedziałem, że to może się stać –

2

Martin Broadhurst podał już poprawną language-lawyer answer. Mam zamiar dać szczegóły techniczne odpowiedź:

Punkt temat korzystania delete[] nad delete to, że nie ma sposobu, aby operator delete wiedzieć, czy przeszły punktów wskaźnikiem do tablicy lub do pojedynczego obiektu. Jako taki, delete usuwa tylko jeden obiekt, podczas gdy delete[] wywołuje dodatkową magię, aby odzyskać rozmiar tablicy, i kontynuuje usuwanie wszystkich elementów.

Teraz usuwanie składa się z dwóch odrębnych części:

  1. Obiekty muszą być zniszczone przez wywołanie destruktory. W przypadku tablicy oznacza to jedno wywołanie destruktora dla każdego elementu tablicy.

  2. Pamięć, która została użyta musi być oznaczona jako wolna, aby mogła zostać ponownie użyta. Jest to zadanie globalnej wersji operator delete() w C++. Ponieważ tablice są przechowywane kolejno, jest to pojedyncze wywołanie dla całej tablicy.

valgrind dotyczy tylko pamięci. W związku z tym przechwytuje funkcje alokujące pamięć, takie jak: malloc(), , , .

Co się stanie, gdy zadzwonisz pod numer delete zamiast delete[], że pierwszy obiekt zostanie zniszczony, a wskaźnik zostanie przekazany do operator delete().operator delete() nie wie o obiekcie (obiektach), które były przechowywane w obszarze pamięci, są one i tak zniszczone, więc z powodzeniem oznaczy obszar pamięci jako wolny. valgrind widzi to połączenie operator delete() i jest szczęśliwy, ponieważ cała pamięć jest dostępna do ponownego wykorzystania. Jednak Twój kod nie zdołał poprawnie zniszczyć wszystkich elementów oprócz pierwszej. I to jest złe.

+0

kilka dni temu napisałem program. kiedy uruchamiam ten program, wykonanie zadania zajmuje 2 minuty !! ale kiedy używam pakietu 'valgrind', wyjście jest gotowe w ciągu 3 sekund i domyśliłem się, że' valgrind' po prostu zajmuje się płytkim spojrzeniem na kod! Dziękuję za odpowiedź, która jest dla mnie naprawdę pomocna. –

+0

@saeedmasoomi Jeśli jakikolwiek program wykonuje się szybciej w 'valgrind' niż bez, coś jest bardzo nie tak z tym kodem programu:' valgrind' zasadniczo wykonuje program z emulowanym procesorem, który dodaje kontrole graniczne przy każdym dostępie do pamięci, i te sprawdzenia graniczne biorą czas. Oczekuje się, że każdy proces będzie co najmniej 50 razy wolniejszy, gdy zostanie wykonany w trybie "valgrind". Odwrotność oznacza, że ​​twój program robi coś zupełnie innego, gdy działa pod 'valgrind', co oznacza, że ​​wykazuje niezdefiniowane zachowanie. Gdybym był tobą, zdecydowanie bym to zbadał. – cmaster

+0

dziękuję, sprawdzam to i środowisko wykonawcze jest takie samo w obu. –