Kada naudoti malloc vs new?

Matau, kad C + + yra keletas būdų, kaip priskirti ir laisvai naudoti duomenis, ir suprantu, kad, kai skambinate malloc turite skambinti free , o naudodami new operatorių turite prisijungti, kad delete , ir tai (pvz., Skambinkite free() su tuo, kas buvo sukurta su new operatoriumi, bet nesuprantu, kada turėčiau naudoti malloc / free ir kada turėčiau naudoti new / delete savo realaus pasaulio programose.

Jei esate „C ++“ specialistas, prašome leiskite man žinoti bet kokias nykščio taisykles ar susitarimus, kuriuos jūs laikote šiuo atžvilgiu.

408
08 окт. nustatė Ralph Burgess 08 spalis 2008-10-08 22:47 '08 at 10:47 pm 2008-10-08 22:47
@ 19 atsakymų

Jei esate priversti naudoti C, niekada nenaudokite malloc . Visada naudokite new .

Jei jums reikia didelių duomenų, tiesiog atlikite kažką panašaus:

 char *pBuffer = new char[1024]; 

Būkite atsargūs, nors tai neteisinga:

 //This is incorrect - may delete only one element, may corrupt the heap, or worse... delete pBuffer; 

Vietoj to turėtumėte tai padaryti, kai ištrinate duomenų rinkinį:

 //This deletes all items in the array delete[] pBuffer; 

new raktinis žodis yra C + + metodas ir garantuoja, kad jūsų tipas turės savo konstruktorių . new raktinis žodis taip pat yra saugesnis tipams, o malloc nėra saugus tipams.

Vienintelis būdas manau, kad būtų naudinga naudoti „ malloc , jei reikia pakeisti duomenų buferio dydį . new raktinis žodis neturi panašaus metodo kaip realloc . realloc funkcija gali efektyviau padidinti atminties realloc dydį.

Verta pažymėti, kad jūs negalite maišyti new / free ir malloc / delete .

Pastaba Kai kurie atsakymai į šį klausimą yra neteisingi.

 int* p_scalar = new int(5); // Does not create 5 elements, but initializes to 5 int* p_array = new int[5]; // Creates 5 elements 
335
08 окт. Brian R. Bondy atsakymas 08 okt. 2008-10-08 22:48 '08, 10:48 val. 2008-10-08 22:48

Trumpas atsakymas yra: nenaudokite malloc C + + be jokios priežasties. malloc turi keletą trūkumų, kai jie naudojami su C ++, kuriai new nustatyta, kad jis turi būti įveiktas.

Pataisyti trūkumai Naujas C + + kodui

border=0
  • malloc nėra būdingas jokiu prasmingu būdu. „C ++“ rezultatas turi būti grąžintas void* . Tai gali sukelti daug problemų:

     #include <stdlib.h> struct foo { double d[5]; }; int main() { foo *f1 = malloc(1); // error, no cast foo *f2 = static_cast<foo*>(malloc(sizeof(foo))); foo *f3 = static_cast<foo*>(malloc(1)); // No error, bad } 
  • Tai blogiau nei tai. Jei atitinkamas tipas yra POD (paprastieji seni duomenys) , galite pusiau protingai naudoti „ malloc kad priskirtumėte atmintį, nes f2 veikia pirmame pavyzdyje.

    Tai nėra taip akivaizdu, jei tipas yra POD. Svarbus veiksnys yra tai, kad šis tipas gali keistis iš POD į ne POD be kompiliatoriaus klaidos ir galbūt labai sunku ištaisyti problemas. Pvz., Jei kas nors (galbūt kitas programuotojas, atlikdamas paslaugą, turėjo atlikti daug pakeitimų, nes foo nebėra POD, tada kompiliavimo metu nebūtų akivaizdžios klaidos, pavyzdžiui:

     struct foo { double d[5]; virtual ~foo() { } }; 

    mallocf2 padarys blogą, be jokios akivaizdžios diagnozės. Čia pateiktas pavyzdys yra nereikšmingas, tačiau netyčia galite patekti į ne PODness (pvz., Bazinėje klasėje pridedant ne POD elementą). Jei turite C ++ 11 / padidinti, galite naudoti is_pod kad patikrintumėte šią prielaidą ir is_pod klaidą, jei ne:

     #include <type_traits> #include <stdlib.h> foo *safe_foo_malloc() { static_assert(std::is_pod<foo>::value, "foo must be POD"); return static_cast<foo*>(malloc(sizeof(foo))); } 

    Nors padidėjimas negali nustatyti, ar POD tipas yra be C ++ 11, ar kai kurių kitų kompiliatorių plėtinių.

  • malloc grąžina NULL jei paskirstymas nepavyksta. new bus mesti std::bad_alloc . Vėlesnis elgesys su NULL rodykle yra neapibrėžtas. Išimtis turi gryną semantiką, kai ji yra išmesta, ir ji yra išmesta iš klaidos šaltinio. malloc apvalkalas su atitinkama tešla kiekviename kvietime atrodo nuobodus ir klaidingas. (Jūs turite tik vieną kartą pamiršti, kad panaikintumėte šį gerą darbą). Išimtis gali būti leidžiama skleisti iki tokio lygio, kuriuo skambinantysis gali protingai elgtis, kai, kaip NULL daug sunkiau sugrįžti prasmingai. Mes galime išplėsti savo safe_foo_malloc funkciją, kad safe_foo_malloc išimtį arba išeitume iš programos arba skambint kai safe_foo_malloc :

     #include <type_traits> #include <stdlib.h> void my_malloc_failed_handler(); foo *safe_foo_malloc() { static_assert(std::is_pod<foo>::value, "foo must be POD"); foo *mem = static_cast<foo*>(malloc(sizeof(foo))); if (!mem) { my_malloc_failed_handler(); // or throw ... } return mem; } 
  • Iš esmės, malloc yra C funkcija, o new yra C ++ funkcija. Dėl to, „ malloc “ netinkamai žaidžia su konstruktoriais, tik svarsto dalį baitų. safe_foo_malloc norite naudoti new vietą, safe_foo_malloc dar labiau išplėsti „ safe_foo_malloc :

     #include <stdlib.h> #include <new> void my_malloc_failed_handler(); foo *safe_foo_malloc() { void *mem = malloc(sizeof(foo)); if (!mem) { my_malloc_failed_handler(); // or throw ... } return new (mem)foo(); } 
  • Mūsų „ safe_foo_malloc funkcija nėra labai universali - idealiu atveju mums reikia kažko, kas gali dirbti bet kokio tipo, o ne tik foo . Tai galime pasiekti naudojant šablonus ir variantų modelius, taikomus ne numatytiesiems konstruktoriams:

     #include <functional> #include <new> #include <stdlib.h> void my_malloc_failed_handler(); template <typename T> struct alloc { template <typename ...Args> static T *safe_malloc(Args args) { void *mem = malloc(sizeof(T)); if (!mem) { my_malloc_failed_handler(); // or throw ... } return new (mem)T(std::forward(args)...); } }; 

    Dabar, nors sprendžiant visas nustatytas problemas, mes praktiškai iš naujo nustatėme new standartinį operatorių. Jei ketinate naudoti „ malloc ir naują vietą, galite tiesiog naudoti new kad pradėtumėte!

123
01 нояб. Atsakymas pateikiamas Flexo 01 lapkričio. 2011-11-01 20:04 '11, 20:04, 2011-11-01 20:04

C ++ FQA Lite :

[16.4] Kodėl turėčiau naudoti naujus, o ne patikimus senus malloc ()?

Dažniausiai užduodami klausimai: naujas / ištrinti konstruktorius / destruktorius; Naujas tipas yra saugus, malloc nėra; naujas gali būti panaikintas pagal klasę.

FQA: Dažnai užduodamuose klausimuose paminėtų naujų dalykų privalumai nėra dorybės, nes konstruktoriai, destruktoriai ir operatoriaus perkrovos yra šiukšlės (žr., Kas atsitinka, kai neturite šiukšlių surinkimo?), Ir saugumo tipas yra labai mažas ( turėtų atmesti tuštumą *, grįžo malloc į tinkamą rodyklės tipą, priskirti jį įvestam rodyklės kintamajam, kuris gali būti erzina, bet toli nuo „nesaugaus“).

O, ir naudojant patikimą seną malloc leidžia naudoti patikimą ir seną realloc. Gaila, kad neturime naujo puikaus naujo operatoriaus ar panašaus.

Tačiau naujasis nėra toks blogas, kad pateisintų nukrypimą nuo bendrojo stiliaus, naudojamo visoje kalboje, net jei kalba yra C ++. Visų pirma, klasės, kuriose yra ne trivialūs konstruktoriai, klaidingai elgsis su mirtimis, jei esate tik malloc objektai. Tad kodėl gi ne naudoti naują kodą? Žmonės retai perkrauna naują operatorių, todėl jis tikriausiai nepateks į jūsų per daug. Ir jei jie perkrauna naują, visada galite paprašyti jų sustoti.

Atsiprašau, aš tiesiog negalėjau atsispirti. :)

48
08 окт. Matthias Benkard atsakymas 2008-10-08 23:24 '08 at 23:24 pm 2008-10-08 23:24

Visada naudokite naują „C ++“. Jei reikia atminties bloko, galite tiesiogiai naudoti naują operatorių:

 void *p = operator new(size); ... operator delete(p); 
46
08 окт. atsakymas duotas Ferruccio 08 okt. 2008-10-08 22:54 '08 10:54 val. 2008-10-08 22:54

Naudokite „ malloc ir free naudokite tik atminties priskyrimą, kurį valdys c-centrinės bibliotekos ir API. Visiems, kuriuos valdote, naudokite new ir delete (ir [] parinktis).

27
08 окт. atsakymas ddckee 08 oct. 2008-10-08 22:51 '08, 10:51 val. 2008-10-08 22:51

naujas vs malloc ()

1) new yra operatorius , o malloc() yra funkcija .

2) new skambučių konstruktoriai , bet malloc() ne.

3) new grąžina tikslų duomenų tipą , o malloc() grąžina tuščią * .

4) new niekada negrąžina NULL (nepavyks), o malloc() grąžina NULL

5) new atminties perskirstymas neapdorojamas, o malloc() gali

23
26 нояб. Yogeesh HT lapkričio 26 d. 2015-11-26 13:06 '15, 13:06 2015-11-26 13:06

Norint atsakyti į jūsų klausimą, reikia žinoti skirtumą tarp malloc ir new . Skirtumas yra paprastas:

malloc skiria atmintį , o new skiria atmintį, ir skambina objekto, kuriam skiriate atmintį, konstruktorių.

Taigi, jei neapsiribojate C, niekada nenaudokite malloc, ypač dirbant su C ++ objektais. Tai bus jūsų programos įsilaužimo receptas.

Be to, skirtumas tarp free ir delete toks pats. Skirtumas yra tas, kad delete sukels jūsų objekto sunaikintuvą be atminties.

12
29 июля '17 в 10:20 2017-07-29 10:20 Atsakymą pateikia „Quantum Physicist“ liepos 29 d. 17 d. 10:20 2017-07-29 10:20

Yra vienas didelis skirtumas tarp malloc ir new . malloc skiria atmintį. Tai normalu C, nes C atmintyje yra objektas.

C + +, jei nesate susiję su POD tipais (kurie yra panašūs į C tipus), turite iškviesti konstruktorių atminties ląstelėje, kad būtų iš tikrųjų objektas. Ne POD tipai yra labai dažni C ++, nes daugelis C ++ funkcijų objektą automatiškai sudaro ne POD.

new priskiria atmintį ir sukuria objektą šioje atminties vietoje. Ne POD tipams tai reiškia, kad reikia skambinti konstruktoriui.

Jei tai darote:

 non_pod_type* p = (non_pod_type*) malloc(sizeof *p); 

Nurodytas žymeklis negali būti pašalintas, nes jis nenurodo objekto. Prieš naudodami jį turėsite paskambinti statytojui (ir tai daroma naudojant new vietą).

Kita vertus, jei darote:

 non_pod_type* p = new non_pod_type(); 

Gausite rodyklę, kuri visada galioja, nes new sukūrė objektą.

Net ir POD tipams yra didelis skirtumas tarp jų:

 pod_type* p = (pod_type*) malloc(sizeof *p); std::cout << p->foo; 

Šis kodas bus išspausdintas neapibrėžta reikšme, nes POD objektai, sukurti naudojant „ malloc , nėra inicijuojami.

Naudodami new galite nurodyti konstruktorių, kuriam reikia skambinti, ir gauti tiksliai apibrėžtą vertę.

 pod_type* p = new pod_type(); std::cout << p->foo; // prints 0 

Jei tikrai norite, galite naudoti new kad gautumėte nežinomus POD objektus. Daugiau informacijos rasite kitame atsakyme .

Kitas skirtumas yra gedimo elgesys. Nepavykus priskirti atminties, malloc grąžina nulinį rodiklį, o new metimai - išimtis.

Pirmiausia reikia patikrinti kiekvieną rodyklę, kuri buvo grąžinta prieš naudojimą, o vėlesnė versija visada grąžins galiojančius rodiklius.

Dėl šių priežasčių C + + kodu turėtumėte naudoti new , o ne malloc . Bet netgi tada jūs neturėtumėte naudoti new nes jis įgyja išteklių, kuriuos jums reikia išleisti vėliau. Naudodami new , turite nedelsiant perduoti rezultatą išteklių valdymo klasei:

 std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak 
9
01 нояб. atsakymą pateikė R. Martinho Fernandes lapkričio 01 d. 2011-11-01 21:25 '11, 21:25, 2011-11-01 21:25

Yra keletas new dalykų, kuriuos malloc nedaro:

  • new sukuria objektą, remdamasis šio objekto konstruktoriumi.
  • new nereikalauja priskiriamos atminties įvedimo.
  • Tam nereikia atminties paskirstymo, tačiau reikia sukurti kelis objektus.

Taigi, jei naudojate „ malloc , tuomet jums reikia padaryti aiškesnius dalykus, kurie ne visada yra praktiški. Be to, new gali būti perkrauti, tačiau malloc negali būti.

6
15 янв. Atsakymas duotas herohuyongtao sausio 15 d 2014-01-15 17:45 '14, 17:45 pm 2014-01-15 17:45

Jei dirbate su duomenimis, kuriems nereikia statyti / sunaikinti ir kuriems reikalingas perskirstymas (pvz., Didelis intarpas), manau, kad malloc / free yra geras pasirinkimas, nes jis suteikia jums reallocą, kuris yra daug greitesnis nei naujasis atmintis -delete (tai yra mano „Linux“ >

Bet kokiu atveju, nesuprantu, kodėl jūs neturėtumėte naudoti abiejų (jei atlaisvinsite suklastotą atmintį ir ištrinsite naujai priskirtus objektus), jei galite naudoti greičio pagreitį (kartais reikšmingą, jei perskirstysite didelius POD masyvus) realloc gali suteikti jums.

Jei to nereikia, turėtumėte prilipti nauju / ištrintu C + +.

4
09 апр. atsakymas pateikiamas PSkocik 09 balandžio. 2013-04-09 15:23 '13, 15:23, 2013-04-09 15:23

Jei naudojate C ++, pabandykite naudoti naują / ištrinti vietoj malloc / calloc, nes jie yra operatoriai. Malloc / calloc atveju turite įtraukti kitą antraštę. Nemaišykite dviejų skirtingų kalbų tame pačiame kode. Jų darbas visais atžvilgiais yra tas pats, tiek dinamiškai skirstant atmintį iš krūvos segmento į maišos lentelę.

3
02 апр. atsakymą pateikė user3488100 02 apr. 2014-04-02 12:13 '14, 12:13, 2014-04-02 12:13

Jei turite C kodą, kurį norite perkelti į „C ++“, galite palikti visus skambučius į „malloc“ (). Bet kokiam naujam C + + kodui rekomenduoju jį naudoti.

3
08 окт. Fred Larson atsakymas, 08 spalis 2008-10-08 22:52 '08, 10:52 val. 2008-10-08 22:52

Mažesniu požiūriu naujoji atmintis pradės inicijuoti visą atmintį, o malloc išsaugos pradinį atminties turinį.

1
14 авг. Atsakymą pateikė Peiti Peter Li 14 rug . 2011-08-14 23:31 '11 11:31 val. 2011-08-14 23:31

new inicijuoja numatytąsias struktūros vertes ir teisingai susieja joje esančias nuorodas.

Pavyzdžiui.

 struct test_s { int some_strange_name = 1; int  = some_strange_name; } 

Taigi, new struct test_s grąžina inicijuotą struktūrą su darbo nuoroda, o malloc'ed versijoje nėra numatytų reikšmių, o statinės nuorodos nėra inicijuojamos.

1
14 дек. atsakymas pateikiamas lama12345 14 dec. 2016-12-14 18:46 '16 at 18:46 2016-12-14 18:46

Dinaminis paskirstymas reikalingas tik tuo atveju, jei objekto eksploatavimo trukmė turėtų skirtis nuo srities, kurioje ji sukurta (taip pat taikoma mažinant ir didinant plotą), ir jūs turite ypatingą priežastį, kodėl taupymas pagal vertę nėra darbas.

Pavyzdžiui:

  std::vector<int> *createVector(); // Bad std::vector<int> createVector(); // Good auto v = new std::vector<int>(); // Bad auto result = calculate( v); auto v = std::vector<int>(); // Good auto result = calculate( > 

Pradedant nuo C ++ 11, turime std::unique_ptr kad std::unique_ptr dirbti su paskirta atmintimi, kurioje yra priskirtos atminties savininkas. std::shared_ptr buvo sukurtas std::shared_ptr kai turėtumėte bendrinti turtą. (jums reikia mažiau, nei tikitės geroje programoje)

Pavyzdžio sukūrimas tampa tikrai paprastas:

 auto instance = std::make_unique<Class>(); // C++14 auto instance = std::make_unique<Class>(new Class()); // C++11 auto instance = std::make_unique<Class[]>(42); // C++14 auto instance = std::make_unique<Class[]>(new Class[](42)); // C++11 

„C ++ 17“ taip pat prideda std::optional kuris gali neleisti jums reikalauti atminties.

 auto optInstance = std::optional<Class>{}; if (condition) optInstance = Class{}; 

Kai tik „egzempliorius“ išeina iš taikymo srities, atmintis išvaloma. Taip pat paprastas nuosavybės perdavimas:

  auto vector = std::vector<std::unique_ptr<Interface>>{}; auto instance = std::make_unique<Class>(); vector.push_back(std::move(instance)); // std::move -> transfer (most of the time) 

Taigi, kada jums vis dar reikia new ? Beveik niekada su „C ++ 11“ ir kitomis. Dauguma jų naudojate std::make_unique kol jūs std::make_unique į tašką, kur jūs pateksite į API, kuris persiunčia nuosavybę per neapdorotus nurodymus.

  auto instance = std::make_unique<Class>(); legacyFunction(instance.release()); // Ownership being transferred auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr 

C ++ 98/03 turite atlikti rankinį atminties valdymą. Jei šiuo atveju esate, pabandykite atnaujinti naujesnę standarto versiją. Jei esate įstrigę:

  auto instance = new Class(); // Allocate memory delete instance; // Deallocate auto instances = new Class[42](); // Allocate memory delete[] instances; // Deallocate 

Įsitikinkite, kad sekite nuosavybę, kad nebūtų atminties! Perkelti semantiką dar neveikia.

Taigi, kada mums reikia Malloc C + +? Vienintelė priežastis yra atminties paskirstymas ir vėlesnis jo inicijavimas, įterpiant naują.

  auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory auto instance = new(instanceBlob)Class{}; // Initialize via constructor instance.~Class(); // Destroy via destructor std::free(instanceBlob); // Deallocate the memory 

Nors tai yra tiesa, tai taip pat galima atlikti per naują operatorių. std::vector yra geras pavyzdys.

Galiausiai, kambaryje vis dar yra dramblys: C Jei turite dirbti su C biblioteka, kurioje atmintis skiriama C + + kodu ir išleista į C kodą (arba atvirkščiai), jūs esate priversti naudoti malloc / free.

Jei esate šiuo atveju, pamiršite apie virtualias funkcijas, nario funkcijas, klases ... Leidžiama naudoti tik struktūras, turinčias POD.

Kai kurios taisyklių išimtys:

  • Jūs rašote standartinę biblioteką su pažangiomis duomenų struktūromis, kur malloc yra tinkamas.
  • Turite skirti daug atminties (failo veikimo kopijoje 10 GB?)
  • Ar turite įrankių, kurie neleidžia naudoti tam tikrų dizainų
  • Turite išsaugoti neišsamius tipus
0
22 дек. Atsakymą pateikė JVApen 22 d. 2018-12-22 21:08 '18, 21:08 2018-12-22 21:08

Retas atvejis yra apsvarstyti galimybę naudoti „malloc“ / „free“, o ne naują / ištrinti, tai yra tada, kai pasirenkate ir po to platinate (paprastus „pod“ tipus, o ne objektus) naudojant „realloc“, nes „C ++“ neturi funkcijos, panašios į realloc (nors tai galima padaryti naudojant daugiau C ++ metodo).

0
29 июля '17 в 9:17 2017-07-29 09:17 Atsakymą pateikė Florentino Tuason , liepos 29 d. 17, 9:17 2017-07-29 09:17

new ir delete operatoriai gali dirbti su klasėmis ir struktūromis, o malloc ir free darbas - tik su atminties blokais, kuriuos reikia atlikti.

Naudojant new/delete padėsite pagerinti jūsų kodą, nes nereikia priskirti priskirtos atminties norimai duomenų struktūrai.

0
08 окт. atsakymą pateikė selwyn spalio 08 d 2008-10-08 23:42 '08 at 23:42 pm 2008-10-08 23:42

Kitame scenarijuje negalime naudoti naujo, nes jis vadina konstruktorių.

 class B { private: B *ptr; int x; public: B(int n) { cout<<"B: ctr"<<endl; //ptr = new B; //keep calling ctr, result is segmentation fault ptr = (B *)malloc(sizeof(B)); x = n; ptr->x = n + 10; } ~B() { //delete ptr; free(ptr); cout<<"B: dtr"<<endl; } }; 
-1
17 авг. atsakymą pateikė Barry 17 d. 2012-08-17 03:54 '12 at 3:54 2012-08-17 03:54

malloc () naudojamas dinamiškai paskirstyti atmintį C, o tas pats darbas atliekamas naudojant naują () C ++. Taigi kodavimo konvencijas negalima maišyti dviem kalbomis. Būtų malonu, jei paprašėte skirtumo tarp calloc ir malloc ()

-4
26 июля '12 в 8:41 2012-07-26 08:41 atsakymą pateikė Hitesas Ahuja, liepos 26 d., 12 d., 8: 41 am 2012-07-26 08:41