Koks naudojimas naudojamas „naujai paskelbti“?

Ar kas nors čia kada nors naudojo „C ++“ naują skelbimą? Jei taip, tai kodėl? Man atrodo, kad tai būtų naudinga tik tada, kai rodoma atminties kortelėje.

358
21 окт. Vadovas Geek rinkinys 21 sp 2008-10-21 19:34 '08, 19:34, 2008-10-21 19:34
@ 22 atsakymai

Naujo leidimas leidžia sukurti objektą atmintyje, kuri jau yra priskirta.

Galbūt norėsite tai padaryti optimizuojant, kai reikia sukurti kelis objekto egzempliorius, o ne kartą perskirstyti atmintį kiekvieną kartą, kai jums reikia naujo pavyzdžio. Vietoj to, gali būti veiksmingiau atlikti vieną priskyrimą atminties vienetui, kuriame gali būti keli objektai, net jei nenorite, kad visa tai būtų naudojama vienu metu.

DevX suteikia gerą pavyzdį :

C ++ standartas taip pat palaiko naują pareiškimą, kuris sukuria objektą iš anksto paskirstytame buferyje. Tai naudinga kuriant atminties talpyklą, šiukšlių rinktuvą arba tiesiog tada, kai svarbiausios yra veiklos ir saugumo išimtys (nėra jokio paskirstymo gedimo pavojaus, nes atmintis jau priskirta, o objekto kūrimas anksčiau priskirtame buferyje trunka mažiau laiko):

 char *buf = new char[sizeof(string)]; // pre-allocated buffer string *p = new (buf) string("hi"); // placement new string *q = new string("hi"); // ordinary heap allocation 

Taip pat galite būti tikri, kad tam tikroje kritinio kodo dalyje gali nebūti paskirstymo klaidos (pvz., Širdies stimuliatoriaus atliekamame kode). Tokiu atveju, norėsite priskirti atmintį prieš ir tada naudoti naują vietą kritiniame skyriuje.

Paskirstymas naujose

Jums nereikia išlaisvinti kiekvieno objekto, kuris naudoja atminties buferį. Vietoj to turėtumėte ištrinti [] tik originalų buferį. Tada jūs turite skambinti savo klasių destruktorius rankiniu būdu. Norėdami gauti gerą pasiūlymą šiuo klausimu, žr. Skyrių „Klausimai ir atsakymai apie Stroustrup“: ar yra „vieta“ ?

330
21 окт. Brian R. Bondy atsakymas, pateiktas spalio 21 d 2008-10-21 19:41 '08 at 7:41 pm 2008-10-21 19:41

Naudojame jį su vartotojo atminties grupėmis. Tik eskizas:

 class Pool { public: Pool() {  }; virtual ~Pool() {  }; virtual void *allocate(size_t); virtual void deallocate(void *); static Pool::misc_pool() { return misc_pool_p;  } }; class ClusterPool : public Pool {  }; class FastPool : public Pool {  }; class MapPool : public Pool {  }; class MiscPool : public Pool {  }; // elsewhere... void *pnew_new(size_t size) { return Pool::misc_pool()->allocate(size); } void *pnew_new(size_t size, Pool *pool_p) { if (!pool_p) { return Pool::misc_pool()->allocate(size); } else { return pool_p->allocate(size); } } void pnew_delete(void *p) { Pool *hp = Pool::find_pool(p); // note: if p == 0, then Pool::find_pool(p) will return 0. if (hp) { hp->deallocate(p); } } // elsewhere... class Obj { public: // misc ctors, dtors, etc. // just a sampling of new/del operators void *operator new(size_t s) { return pnew_new(s); } void *operator new(size_t s, Pool *hp) { return pnew_new(s, hp); } void operator delete(void *dp) { pnew_delete(dp); } void operator delete(void *dp, Pool*) { pnew_delete(dp); } void *operator new[](size_t s) { return pnew_new(s); } void *operator new[](size_t s, Pool* hp) { return pnew_new(s, hp); } void operator delete[](void *dp) { pnew_delete(dp); } void operator delete[](void *dp, Pool*) { pnew_delete(dp); } }; // elsewhere... ClusterPool *cp = new ClusterPool(arg1, arg2, ...); Obj *new_obj = new (cp) Obj(arg_a, arg_b, ...); 
border=0

Dabar galite sugrupuoti objektus vienoje atminties arenoje, pasirinkti labai greitą skirstytuvą, tačiau neatlaisvinti atminties, naudoti atminties žemėlapius ir bet kurį kitą semantiką, kurią norite įvesti, pasirinkti baseiną ir perduoti jį kaip argumentą naujam objektų paskirstymo operatoriui.

51
21 окт. atsakymas į Don Wakefield spalio 21 d. 2008-10-21 19:52 '08 at 7:52 pm 2008-10-21 19:52

Tai naudinga, jei norite atskirti pasirinkimą nuo iniciacijos. STL naudoja naują išdėstymą, kad sukurtų konteinerio elementus.

45
21 окт. atsakymas pateiktas MSN 21 spalis 2008-10-21 19:40 '08 at 7:40 pm 2008-10-21 19:40

Aš jį panaudojau realiu laiku. Paprastai mes nenorime atlikti dinaminio paskyrimo (arba paleidimo) po sistemos paleidimo, nes nėra jokių garantijų, kiek laiko užtruks.

Ką aš galiu padaryti, yra iš anksto nustatyti daug atminties (pakankamai didelis, kad galėtumėte turėti bet kokią sumą, kurią gali prireikti klasėje). Tada, kai išsiaiškinsiu, kaip sukurti daiktus, galite naudoti naują vietą, kad sukurtumėte objektus, kur noriu. Viena iš situacijų, kurias aš žinau, padėjo sukurti heterogeninį apykaitinį buferį .

Tai, žinoma, nėra už silpną širdį, bet dėl ​​to, kad jie sintaksę jam daro gana grubus.

29
21 окт. atsakymas pateiktas TED 21 okt. 2008-10-21 20:58 '08 at 8:58 pm 2008-10-21 20:58

Naudojau ją kuriant objektus, dedamus ant kamino, naudodamiesi asigna ().

negailestingas kištukas: apie tai čia parašiau.

21
21 окт. atsakymas duotas Ferruccio 21 okt. 2008-10-21 19:51 '08 at 7:51 pm 2008-10-21 19:51

Vadovas Geek: BINGO! Jūs turite jį visiškai - būtent tai tinka. Daugelyje įterptųjų aplinkų išoriniai suvaržymai ir (arba) bendras naudojimo scenarijus verčia programuotoją atskirti objekto atranką nuo jo inicijavimo. Kartu sujungtas „C ++“ vadina „instanciją“; bet kai konstruktoriaus veiksmas turi būti aiškiai pareikštas be dinamiško ar automatinio paskirstymo, naujo pateikimas yra būdas tai padaryti. Tai taip pat idealus būdas rasti pasaulinį C ++ objektą, susietą su aparatinės įrangos komponento adresu (I / O su atmintimi) arba bet kokiam statiniam objektui, kuris dėl kokios nors priežasties turi būti fiksuotu adresu.

12
16 июля '10 в 20:47 2010-07-16 20:47 atsakymas dorcsssc duotas liepos 16 d. 10 val. 20:47 2010-07-16 20:47

Naudojau ją kuriant klasės variantą (t. Y. Objektą, kuris gali atstovauti vienai vertei, kuri gali būti viena iš kelių skirtingų tipų).

Jei visos vertės klasės, kurias palaiko „Variant“ klasė, yra POD tipai (pvz., „Int“, „float“, „double“, „bool“), tada C stiliaus trukdančioji sąjunga yra pakankama, bet jei norite, kad kai kurie vertės tipai būtų „C ++“ objektai (pvz., std :: string), C sąjungos funkcija nebus vykdoma, nes duomenų tipai, išskyrus POD, negali būti deklaruojami kaip sąjungos dalis.

Taigi, aš skiriu pakankamai didelį baitų masyvą (pavyzdžiui, sizeof (the_largest_data_type_I_support)) ir naudokite naują vietą, kad inicijuotumėte atitinkamą C + + objektą šioje srityje, kai Variantas yra nustatytas išsaugoti šio tipo vertes. (Ir, jei, žinoma, perkeliate iš kitokio tipo nei POD), vieta ištrinama iš anksto

11
23 мая '13 в 8:10 2013-05-23 08:10 Atsakymą pateikė Jeremy Friesner , gegužės 23 d., 13 val

Tai taip pat naudinga, jei norite atkurti pasaulines ar statiškai paskirstytas struktūras.

Senasis C metodas, kurį naudojo „ memset() , nustatė visus elementus į 0. Jūs negalite to padaryti „C ++“ dėl vtables ir pasirinktinių objektų konstruktorių.

Todėl kartais naudoju toliau nurodytus veiksmus

  static Mystruct m; for(...) { // re-initialize the structure. Note the use of placement new // and the extra parenthesis after Mystruct to force initialization. new ( Mystruct(); // do-some work that modifies m content. } 
9
04 апр. atsakymas pateikiamas nimrodm 04 balandžio. 2013-04-04 11:29 '13, 11:29, 2013-04-04 11:29

Tai naudinga, jei kuriate branduolį - kur įdėjote branduolio kodą, kurį skaitote iš disko ar į tinklapį? Jūs turite žinoti, kur šokti.

Arba kitais, labai retais atvejais, pvz., Kai turite daug įkeltų patalpų ir norite vienas po kito pastatyti kelias struktūras. Tokiu būdu jie gali būti pakuojami nenaudojant offsetof () operatoriaus. Tačiau yra ir kitų triukų.

Taip pat manau, kad kai kuriuose STL diegimuose naudojama nauja vieta, pvz., Std :: vektorius. Taigi jie skiria erdvę 2 ^ n elementams ir ne visada turi realaus.

8
21 окт. atsakymas, pateiktas mstrobl sp. 21 d 2008-10-21 19:38 '08, 07:38 pm 2008-10-21 19:38

Naujas įdėjimas taip pat yra labai naudingas serializuojant (pvz., Su padidinimu :: serializacija). 10 metų amžiaus C + + yra tik antras kartas, kai man reikia naujos vietos (trečia, jei įtraukiate interviu)).

8
05 апр. Atsakymą pateikė RichardBruce 05 Bal. 2013-04-05 03:45 '13, 3:45, 2013-04-05 03:45

Jis naudoja std::vector<> , nes std::vector<> paprastai skiria daugiau atminties nei objects vector<> .

7
21 окт. atsakymas į Andreas Magnusson spalio 21 d 2008-10-21 19:41 '08 at 7:41 pm 2008-10-21 19:41

Manau, kad tai nebuvo pabrėžta jokiu atsakymu, bet dar vienas geras pavyzdys ir naudojimas naujai vietai yra sumažinti atminties fragmentaciją (naudojant atminties baseinus). Tai ypač naudinga įterptoms ir aukšto prieinamumo sistemoms. Pastaruoju atveju tai ypač svarbu, nes sistemai, kuri turėtų veikti 24/365 dienas, labai svarbu, kad nebūtų susiskaidymo. Ši problema neturi nieko bendro su atminties nutekėjimu.

Net jei naudojamas labai geras „malloc“ (arba panašios atminties valdymo funkcijos) įgyvendinimas, labai sunku ilgai išspręsti susiskaidymą. Tam tikru momentu, jei nežinote, kaip efektyviai naudoti atminties rezervavimo / išleidimo skambučius, galite gauti daug mažų erdvių , kurias sunku pakartotinai naudoti (priskirti naujas rezervacijas). Taigi, vienas iš sprendimų, naudojamų šiuo atveju, yra naudoti atminties talpą, skirtą priskirti atmintį taikomiesiems objektams. Kiekvieną kartą, kai reikia objekto atminties, tiesiog naudokite naują vietą, kad sukurtumėte naują objektą jau rezervuotoje atmintyje.

Taigi, paleisdami programą, jau turite visą reikalingą atmintį. Visos naujos atminties atsarginės kopijos / užšaldymai priskiriami baseinams (galite turėti kelis baseinus, po vieną kiekvienai objektų klasei). Šiuo atveju nėra atminties fragmentacijos, nes nebus tarpų, ir jūsų sistema gali dirbti labai ilgai (metus) be fragmentacijos.

Mačiau tai praktikoje specialiai VXWorks RTOS, nes jos numatytoji atminties paskirstymo sistema labai nukenčia nuo susiskaidymo. Todėl atminties skyrimas naudojant standartinį naują / „malloc“ metodą projekte buvo uždraustas. Visos atminties rezervacijos turi būti nukreiptos į specialią atminties talpą.

7
01 окт. atsakymas pateikiamas rkachach 01 okt. 2015-10-01 16:44 '15, 16:44 2015-10-01 16:44

Aš jį panaudojau objektams saugoti su failais su atminties žemėlapiu.
Konkretus pavyzdys buvo vaizdų duomenų bazė, kuri apdorojo didelį skaičių didelių vaizdų (daugiau nei ji gali būti pritaikyta atmintyje).

6
21 окт. Martin Beckett atsakymas, pateiktas spalio 21 d 2008-10-21 19:38 '08, 07:38 pm 2008-10-21 19:38

Tiesą sakant, jums reikia įdiegti bet kokią duomenų struktūrą, kuri skiria daugiau atminties nei minimalus reikalingas įvestų elementų skaičiui (t. Y. Nieko, išskyrus susijusią struktūrą, kuri vienu metu paskirsto vieną mazgą).

Paimkite talpyklas, pvz., deque , vector arba deque . Visi jie skiria daugiau atminties nei minimalus reikalingas elementams, kuriuos norite įterpti, kad kiekvienam atskiram įdėklu nereikėtų paskirstyti krūvos. Naudokime vector kaip paprasčiausią pavyzdį.

Paleidus:

<Pre> <code> vektorius <Foo> VEC; // Paskirti atmintį tūkstančiams „Foos“: vec.reserve (1000); Kodas>

... kuri iš tikrųjų nesukuria tūkstančių Foosų. Jis tiesiog skiria / rezervuoja atmintį. Jei vector čia nenaudojo, tai būtų numatytoji „ Foos konstrukcija aplink vietą, ir būtinybė skambinti jų sunaikintuvams netgi elementams, kurių jūs net neįdėjote.

Pasiskirstymas! = Statyba, išlaisvinimas = sunaikinimas

Paprastai, norint įgyvendinti daugelį duomenų struktūrų, kaip aprašyta aukščiau, negalite matyti atminties paskirstymo ir elementų kūrimo kaip vieno nedalomo dalyko, taip pat negalite peržiūrėti atminties ir elementų ištrynimo kaip vieno nedalomo dalyko.

Būtina atskirti šias idėjas, kad nereikėtų be reikalo skambinti konstruktoriams ir destruktoriams be reikalo į kairę ir į dešinę, todėl standartinė biblioteka dalijasi idėja, kad std:: allocator (kuris nesukuria ar nesunaikina elementų, kai skiria / atleidžia atmintį *). naudojamas, kad rankiniu būdu sukuriant elementus, įdėdami naujus ir rankiniu būdu ištrinant elementus, naudojant aiškius skambučius į destruktorius.

  • Aš nekenčiu std:: allocator dizaino, bet tai dar vienas dalykas, apie kurį kalbėsiu: - D

Bet kokiu atveju, aš linkęs jį naudoti labai daug, nes parašiau kelis universalius standartinius C + + konteinerius, kurie negali būti sukurti esamų. Tarp jų yra nedidelis vektorių įgyvendinimas, kurį prieš kelis dešimtmečius pastatiau, kad būtų išvengta krūvos pasiskirstymo normaliais atvejais, ir efektyvus atminties valdymas (nesuteikia vieno mazgo vienu metu). Abiem atvejais aš negalėjau jas įgyvendinti naudojant esamus konteinerius, todėl turėjau naudoti placement new kad išvengtumėme be reikalo skambinti konstruktoriams ir destruktoriams nereikalingų dalykų kairėje ir dešinėje.

Žinoma, jei kada nors dirbote su priskirtais paskirstytojais, kad pasirinktumėte objektus atskirai, pvz., Nemokamam sąrašui, taip pat paprastai norėtumėte naudoti placement new , pvz., Tai (pagrindinis pavyzdys, kuris neapsunkina išimties saugumo ar RAII):

  Foo * foo = new (free_list.allocate()) Foo (...); ... foo- > ~ Foo(); free_list.free(Foo); Код> 
6
16 янв. Atsakymą pateikė Dragon Energy sausio 16 d. 2018-01-16 06:43 '18, 6:43 2018-01-16 06:43

Aš jį panaudojau objektams kurti pagal atmintį, kurioje yra pranešimų, gautų iš tinklo.

6
21 окт. Steve Fallows spalio 21 d 2008-10-21 20:01 '08 8:01 pm 2008-10-21 20:01

Mačiau, kad jis buvo naudojamas kaip nedidelis „dinaminio tipo“ rodyklės našumo įsilaužimas (skiltyje „Po gaubtu“)

Bet čia yra išradingas triukas, kurį aš greitai dirbau mažų tipų atveju: jei laikoma vertė gali būti tinkama negaliojančiai *, aš iš tikrųjų nenoriu pasirinkti naujo objekto, priversiu jį naudoti pačiame žymeklyje naudojant naują vietą.

6
21 окт. atsakymas, pateiktas Max Lybbert , spalio 21 d 2008-10-21 23:23 '08, 23:23 pm 2008-10-21 23:23

Kaip taisyklė, naujo pateikimas naudojamas norint atsikratyti „normalaus naujo“ platinimo išlaidų.

Kitas scenarijus, kai aš jį panaudojau, kur norėjau pasiekti rodyklę prie objekto, kuris vis dar turėjo būti pastatytas, siekiant įgyvendinti vienintelį dokumentą.

5
21 окт. atsakymas duotas xtofl 21 okt. 2008-10-21 20:32 '08 8:32 2008-10-21 20:32
5
28 авг. atsakymą pateikė kralyk 28 rug . 2012-08-28 23:52 '12 11:52 val. 2012-08-28 23:52

Viena vieta, per kurią patekau, yra konteineriuose, skiriančiuose gretimą buferį, ir tada užpildykite jį objektais. Kaip minėta, std :: vektorius tai gali padaryti, ir žinau, kad kai kurios MFC CArray ir / arba CList versijos tai padarė (nes ten, kur pirmą kartą susidūriau). Buferio perskirstymo metodas yra labai naudingas optimizavimas, ir naujo pateikimas yra vienintelis būdas sukurti scenarijų objektus. Kartais jis naudojamas ir objektams kurti atminties blokuose, kurie yra priskirti ne jūsų tiesioginiam kodui.

Aš jį panaudojau panašiu pajėgumu, nors dažnai taip nėra. Tai yra naudinga priemonė C ++ įrankių rinkiniui.

4
21 окт. atsakymas pateikiamas Nick 21 okt. 2008-10-21 21:13 '08 at 9:13 pm 2008-10-21 21:13

Scenarijaus varikliai gali naudoti jį savo sąsajoje, kad pasirinktų savo objektus iš scenarijų. Pavyzdžiui, žr. „Angelscript“ (www.angelcode.com/angelscript).

4
22 окт. atsakymas, kurį pateikė Raindog, spalio 22 d. 2008-10-22 00:27 '08 0:27 2008-10-22 00:27

Žr. „Fp.h“ failą „xll“ projekte adresu http://xll.codeplex.com.Jis išsprendžia „nepagrįsto chumminess su kompiliatoriumi“ problemą masyvams, kurie, atrodo, atlieka matavimus aplink juos.

 typedef struct _FP { nepasirašytos trumpos eilutės; nepasirašytos trumpos int stulpeliai; dvigubas masyvas [1];  / * Tiesą sakant, masyvas [eilutės] [stulpeliai] * / } FP;
3
26 янв. Keith A. Lewis paskelbė sausio 26 d 2011-01-26 23:03 '11, 23:03, 2011-01-26 23:03

Tai naudoja „C + +“ svetainės konstruktoriaus žudiklį: suderinimą su talpyklos linija, taip pat kitus leidimus su dviem sienomis. Čia yra mano itin greitas algoritmas, skirtas nukreipti žymeklį į bet kurią 2 ribų galią su 5 ar mažiau vieno galo instrukcijomis :

  template <typename T = char> inline T* AlignUp(void* pointer, uintptr_t boundary_byte_count) { uintptr_t value = reinterpret_cast<uintptr_t>(pointer); value += (((~value) + 1)  (boundary_byte_count - 1)); return reinterpret_cast<T*>(value); } struct Foo { Foo () {} }; char buffer[sizeof (Foo) + 64]; Foo* foo = new (AlignUp<Foo> (buffer, 64)) Foo (); 

Dabar ne tik šypsosi ant veido (:-). i C ++ 1x

2
30 июля '18 в 5:00 2018-07-30 05:00 atsakymą pateikė vartotojo2356685 liepos 30 d. 18 val