Widzę w C ++, że istnieje wiele sposobów przydzielania i bezpłatnego przesyłania danych. Rozumiem, że kiedy dzwonisz malloc
, powinieneś zadzwonić, free
a kiedy używasz new
operatora, powinieneś się sparować delete
i błędem jest połączenie tych dwóch (np. Dzwonienie free()
na coś, co zostało stworzone z new
operatorem), ale nie jestem pewien, kiedy powinienem używać malloc
/ free
a kiedy powinienem new
/ delete
w moich prawdziwych programach.
Jeśli jesteś ekspertem w C ++, daj mi znać wszelkie zasady praktyczne i konwencje, które stosujesz w tym zakresie.
c++
memory-management
malloc
new-operator
JVApen
źródło
źródło
Odpowiedzi:
O ile nie jesteś zmuszony do używania C, nigdy nie powinieneś używać
malloc
. Zawsze używajnew
.Jeśli potrzebujesz dużej ilości danych, po prostu zrób coś takiego:
Uważaj, ale to nie jest poprawne:
Zamiast tego powinieneś to zrobić usuwając tablicę danych:
Słowo
new
kluczowe jest sposobem na zrobienie tego w C ++ i zapewni, że Twój typ będzie miał wywołany konstruktor . Słowonew
kluczowe jest również bardziej bezpieczne dla typu, podczas gdy wmalloc
ogóle nie jest bezpieczne dla typu.Jedyny sposób, w jaki mógłbym pomyśleć, że byłby korzystny
malloc
, to gdybyś musiał zmienić rozmiar bufora danych. Słowonew
kluczowe nie ma analogicznego sposobu jakrealloc
.realloc
Funkcja może być w stanie bardziej efektywnie rozszerzyć rozmiar fragmentu pamięci dla ciebie.Warto wspomnieć, że nie można mieszać
new
/free
imalloc
/delete
.Uwaga: niektóre odpowiedzi w tym pytaniu są nieprawidłowe.
źródło
new[]
byłoby znacznie bezpieczniej niżstd::vector
? Jeśli się użyjenew[]
, jedynym sposobem, w jaki wskaźnik stałby się nieprawidłowy, byłby jawnydelete
, podczas gdy pamięć przydzielona dla astd::vector
mogłaby zostać unieważniona, gdy wektor zostanie zmieniony lub pozostanie w zasięgu. (Należy pamiętać, że podczas korzystanianew[]
z niej trzeba by dopuścić możliwość, że ktoś nie będzie w stanie zadzwonić,delete
jeśli metoda asynchroniczna jest nadal w toku; jeśli konieczne może być porzucenie operacji asynchronicznej, konieczne może być zorganizowanie usunięcia przez wywołanie zwrotne) .Krótka odpowiedź brzmi: nie używaj
malloc
do C ++ bez naprawdę dobrego powodu.malloc
ma wiele braków, gdy jest używany z C ++, którynew
został zdefiniowany w celu przezwyciężenia.Niedociągnięcia naprawione przez nowy dla kodu C ++
malloc
nie jest bezpieczny w żaden znaczący sposób. W C ++ musisz przesłać zwrot zvoid*
. To potencjalnie wprowadza wiele problemów:Ale jest gorzej. Jeśli typem jest POD (zwykłe stare dane) , można częściowo rozsądnie użyć
malloc
do przydzielenia pamięci dla niego, takf2
jak w pierwszym przykładzie.Nie jest to jednak takie oczywiste, jeśli typem jest POD. Istotnym czynnikiem jest fakt, że dany typ może przejść z POD na inny niż POD bez wynikającego błędu kompilatora i potencjalnie bardzo trudnych do debugowania problemów. Na przykład, jeśli ktoś (być może inny programista, podczas konserwacji, znacznie później, zrobiłby zmianę, która spowodowała, że
foo
nie jest już POD, to w czasie kompilacji nie pojawiłby się żaden oczywisty błąd, np.może sprawić, że
malloc
zf2
również stać się zły, bez żadnych oczywistych diagnostyki. Ten przykład jest trywialny, ale można przypadkowo wprowadzić non-PODness znacznie dalej (np. W klasie bazowej, dodając element inny niż POD). Jeśli masz C ++ 11 / boost, możesz użyć,is_pod
aby sprawdzić, czy to założenie jest poprawne i spowodować błąd, jeśli nie jest to:Chociaż boost nie jest w stanie określić, czy typ jest POD bez C ++ 11 lub innych rozszerzeń kompilatora.
malloc
zwraca,NULL
jeśli przydział nie powiedzie się.new
rzucistd::bad_alloc
. Zachowanie późniejszego używaniaNULL
wskaźnika jest niezdefiniowane. Wyjątek ma czystą semantykę, gdy jest zgłaszany i jest wyrzucany ze źródła błędu. Opakowaniemalloc
z odpowiednim testem przy każdym połączeniu wydaje się nudne i podatne na błędy. (Musisz tylko raz zapomnieć, aby cofnąć całą tę dobrą pracę). Można zezwolić na wyjątek rozprzestrzeniania się na poziom, na którym osoba dzwoniąca jest w stanie rozsądnie go przetworzyć, gdzieNULL
znacznie trudniej jest sensownie przekazać. Możemy rozszerzyć nasząsafe_foo_malloc
funkcję o zgłoszenie wyjątku lub wyjście z programu lub wywołanie jakiegoś programu obsługi:Zasadniczo
malloc
jest funkcją C inew
jest funkcją C ++. W rezultaciemalloc
nie działa ładnie z konstruktorami, a jedynie zajmuje się przydzielaniem fragmentu bajtów. Moglibyśmy rozszerzyć nasząsafe_foo_malloc
ofertę na korzystanie z miejsc docelowychnew
:Nasza
safe_foo_malloc
funkcja nie jest bardzo ogólna - idealnie chcielibyśmy czegoś, co poradzi sobie z każdym rodzajem, nie tylkofoo
. Możemy to osiągnąć za pomocą szablonów i szablonów variadic dla konstruktorów innych niż domyślne:Teraz jednak naprawiając wszystkie zidentyfikowane dotąd problemy, praktycznie na nowo opracowaliśmy domyślnego
new
operatora. Jeśli zamierzasz używaćmalloc
i umieszczać,new
możesz równie dobrze użyćnew
na początek!źródło
struct
iclass
znaczy w zasadzie to samo; Zastanawiam się, czy wystąpiłyby jakiekolwiek problemy zstruct
zarezerwowaniem POD dla POD i ewentualnieclass
domniemaniem, że wszystkie typy są POD-POD. Wszelkie typy zdefiniowane przez kod, który był wcześniejszy niż wynalazek C ++, koniecznie byłyby POD, więc nie sądzę, że kompatybilność wsteczna byłaby problemem. Czy istnieją zalety posiadania typy nie-pods zadeklarowane jakostruct
zamiastclass
?struct
iclass
zrobienie prawie tego samego było wspaniałą decyzją projektową, która teraz umożliwia zgrabną funkcję o nazwie „metaklasy” (z Herb) .$class
. Nie jestem pewien, co to ma do czynienia zclass
istruct
będących synonimami, jednak.class
i mając nastruct
myśli to samo, możesz dokonywać dowolnych przekształceń na nich ($class
) bez obawy , że zrobiszclass
astruct
i vice versa.Z C ++ FQA Lite :
Przepraszam, po prostu nie mogłem się oprzeć. :)
źródło
Zawsze używaj nowego w C ++. Jeśli potrzebujesz bloku nietypowej pamięci, możesz bezpośrednio użyć operatora new:
źródło
operator new
jestoperator delete
. Wywołaniedelete
wyrażenia typu nie jest dobrze zdefiniowaną czynnościąvoid*
.Używaj
malloc
i tylko do przydzielania pamięci, która będzie zarządzana przez biblioteki i interfejsy API ukierunkowane na c. Użyj i (i wariantów) do wszystkiego, co kontrolujesz.free
new
delete
[]
źródło
malloc
. Podobnie, jeśli taka funkcjastrdup
musi utworzyć obiekt i zwrócić go do obiektu wywołującego, całkowicie uzasadnione jest określenie, że obiekt wywołujący musi wywoływaćfree
obiekt, gdy nie jest on już potrzebny. Jak takie funkcje mogą uniknąć ujawnienia dzwoniącemu korzystania z malloc / free?malloc
C ++?nowy vs malloc ()
1)
new
jest operatorem , natomiastmalloc()
jest funkcją .2)
new
wywołuje konstruktorów , podczas gdymalloc()
nie.3)
new
zwraca dokładny typ danych , amalloc()
zwraca void * .4)
new
nigdy nie zwraca NULL (rzuci w przypadku niepowodzenia), podczas gdymalloc()
zwraca NULL5) Realokacja pamięci nie obsługiwana przez
new
czasmalloc()
możeźródło
char* ptr = new (std::nothrow) char [323232];
new
funkcjarealloc
zamiastmalloc
i zacząć od zainicjowanej zmiennej wskaźnikaNULL
. Z drugiej strony, jeśli chcesz zmienić rozmiar pamięci w C ++, sugerowałbym,std::vector
w przeciwieństwie dorealloc
... Tego lub pliku.Aby odpowiedzieć na twoje pytanie, powinieneś znać różnicę między
malloc
inew
. Różnica jest prosta:malloc
alokuje pamięć , anew
alokuje pamięć ORAZ wywołuje konstruktor obiektu, dla którego alokujesz pamięć.Tak więc, chyba że jesteś ograniczony do C, nigdy nie powinieneś używać malloc, szczególnie w przypadku obiektów C ++. To byłby przepis na zerwanie z programem.
Również różnica między
free
idelete
jest taka sama. Różnica polega na tymdelete
, że oprócz zwalniania pamięci wywoła niszczyciel obiektu.źródło
Jest jedna duża różnica między
malloc
inew
.malloc
przydziela pamięć. Jest to w porządku dla C, ponieważ w C bryła pamięci jest obiektem.W C ++, jeśli nie masz do czynienia z typami POD (które są podobne do typów C), musisz wywołać konstruktor w miejscu pamięci, aby faktycznie mieć tam obiekt. Typy inne niż POD są bardzo popularne w C ++, ponieważ wiele funkcji C ++ powoduje, że obiekt automatycznie nie jest POD.
new
przydziela pamięć i tworzy obiekt w tej lokalizacji pamięci. W przypadku typów innych niż POD oznacza to wywołanie konstruktora.Jeśli zrobisz coś takiego:
Uzyskanego wskaźnika nie można usunąć, ponieważ nie wskazuje on obiektu. Trzeba będzie wywołać na nim konstruktora, zanim będzie można go użyć (i odbywa się to za pomocą umieszczania
new
).Z drugiej strony, jeśli:
Otrzymasz wskaźnik, który jest zawsze poprawny, ponieważ
new
utworzył obiekt.Nawet w przypadku typów POD istnieje znacząca różnica między tymi dwoma:
Ten fragment kodu wypisuje nieokreśloną wartość, ponieważ utworzone obiekty POD
malloc
nie są inicjowane.Za pomocą
new
można określić konstruktora do wywołania, a tym samym uzyskać dobrze zdefiniowaną wartość.Jeśli naprawdę tego chcesz, możesz użyć narzędzia
new
do uzyskania niezainicjowanych obiektów POD. Zobacz tę inną odpowiedź, aby uzyskać więcej informacji na ten temat.Kolejną różnicą jest zachowanie po awarii. Gdy nie uda się przydzielić pamięci,
malloc
zwraca wskaźnik zerowy, anew
zgłasza wyjątek.Pierwszy z nich wymaga przetestowania każdego wskaźnika zwróconego przed jego użyciem, a drugi zawsze będzie generował prawidłowe wskaźniki.
Z tych powodów w kodzie C ++ powinieneś używać
new
, a niemalloc
. Ale nawet wtedy nie powinieneś używaćnew
„na otwartej przestrzeni”, ponieważ zdobywa zasoby, które musisz później uwolnić. Po użyciunew
należy natychmiast przekazać jego wynik do klasy zarządzającej zasobami:źródło
Alokacja dynamiczna jest wymagana tylko wtedy, gdy czas życia obiektu powinien być inny niż zakres, w którym został utworzony (dotyczy to również zmniejszenia zakresu jako większego), a masz konkretny powód, dla którego nie jest przechowywany według wartości praca.
Na przykład:
Od C ++ 11 mamy
std::unique_ptr
do czynienia z przydzieloną pamięcią, która zawiera własność przydzielonej pamięci.std::shared_ptr
został stworzony, gdy musisz współdzielić własność. (będziesz potrzebować tego mniej niż można oczekiwać w dobrym programie)Utworzenie instancji staje się naprawdę łatwe:
C ++ 17 dodaje również,
std::optional
co może zapobiec wymaganiu przydziału pamięciGdy tylko „instancja” zniknie z zakresu, pamięć zostanie wyczyszczona. Przeniesienie własności jest również łatwe:
Więc kiedy nadal potrzebujesz
new
? Prawie nigdy od wersji C ++ 11. Większość z nich używasz,std::make_unique
dopóki nie dojdziesz do punktu, w którym trafisz na interfejs API, który przenosi własność za pomocą surowych wskaźników.W C ++ 98/03 musisz ręcznie zarządzać pamięcią. W takim przypadku spróbuj zaktualizować standard do nowszej wersji. Jeśli utkniesz:
Upewnij się, że śledzisz własność poprawnie, aby nie było wycieków pamięci! Semantyka przenoszenia także jeszcze nie działa.
Kiedy więc potrzebujemy malloc w C ++? Jedynym uzasadnionym powodem byłoby przydzielenie pamięci i zainicjowanie jej później poprzez umieszczenie nowego.
Chociaż powyższe jest ważne, można to zrobić również za pośrednictwem nowego operatora.
std::vector
jest tego dobrym przykładem.Wreszcie mamy jeszcze słonia w pokoju:
C
. Jeśli musisz pracować z biblioteką C, w której pamięć jest przydzielana w kodzie C ++ i uwalniana w kodzie C (lub na odwrót), musisz użyć malloc / free.Jeśli tak jest, zapomnij o funkcjach wirtualnych, funkcjach członkowskich, klasach ... Dozwolone są tylko struktury z POD.
Niektóre wyjątki od zasad:
źródło
Jest kilka rzeczy, które
new
tegomalloc
nie robią:new
konstruuje obiekt, wywołując konstruktor tego obiektunew
nie wymaga rzutowania przydzielonej pamięci.Tak więc, jeśli używasz
malloc
, musisz wyraźnie robić powyższe rzeczy, co nie zawsze jest praktyczne. Dodatkowonew
może być przeciążony, alemalloc
nie może być.źródło
Jeśli pracujesz z danymi, które nie wymagają budowy / zniszczenia i wymagają ponownego przydzielenia (np. Duży wachlarz int), to uważam, że malloc / free to dobry wybór, ponieważ daje ci realokację, która jest znacznie szybsza niż new-memcpy -delete (jest na moim Linux-ie, ale myślę, że może to zależeć od platformy). Jeśli pracujesz z obiektami C ++, które nie są POD i wymagają budowy / zniszczenia, musisz użyć nowych i usuń operatory.
W każdym razie nie rozumiem, dlaczego nie powinieneś używać obu (pod warunkiem, że zwolnisz swoją malloced pamięć i usuniesz obiekty przydzielone z nowym), jeśli możesz skorzystać z przyspieszenia (czasami znaczącego, jeśli przenosisz duże tablice POD), które może dać ci realloc.
O ile nie jest to potrzebne, powinieneś trzymać się nowego / delete w C ++.
źródło
Jeśli masz kod C, który chcesz przenieść do C ++, możesz zostawić w nim wszelkie wywołania malloc (). W przypadku każdego nowego kodu C ++ polecam użycie nowego.
źródło
Jeśli używasz C ++, spróbuj użyć nowego / delete zamiast malloc / calloc, ponieważ są operatorami. W przypadku malloc / calloc musisz dołączyć kolejny nagłówek. Nie mieszaj dwóch różnych języków w tym samym kodzie. Ich praca jest podobna pod każdym względem, obie alokują pamięć dynamicznie z segmentu sterty w tablicy skrótów.
źródło
new
zainicjuje wartości domyślne struktury i poprawnie połączy odnośniki z nim samym.Na przykład
new struct test_s
Zwróci więc zainicjowaną strukturę z działającym odwołaniem, podczas gdy wersja Malloc'ed nie ma wartości domyślnych, a odniesienia do internowania nie są inicjowane.źródło
Z niższej perspektywy, nowa zainicjuje całą pamięć przed jej przekazaniem, podczas gdy malloc zachowa oryginalną zawartość pamięci.
źródło
W poniższym scenariuszu nie możemy użyć nowego, ponieważ wywołuje on konstruktor.
źródło
Te
new
idelete
operatorzy mogą pracować na zajęciach i struktur, podczas gdymalloc
ifree
tylko praca z bloków pamięci, które muszą być odlewane.Użycie
new/delete
pomoże ulepszyć kod, ponieważ nie będziesz musiał rzutować przydzielonej pamięci do wymaganej struktury danych.źródło
Rzadkim przypadkiem, w którym należy rozważyć użycie malloc / free zamiast new / delete, jest przydzielanie, a następnie ponowne przydzielanie (proste typy pod, nie obiekty) za pomocą realloc, ponieważ nie ma podobnej funkcji do realloc w C ++ (chociaż można to zrobić za pomocą więcej podejścia C ++).
źródło
malloc () służy do dynamicznego przydzielania pamięci w C, podczas gdy ta sama praca jest wykonywana przez new () w c ++. Dlatego nie można mieszać konwencji kodowania 2 języków. Byłoby dobrze, gdybyś poprosił o różnicę między calloc a malloc ()
źródło
malloc
w C ++.