Ar tinkamai naudojamas kamino ir krūvos C + +?

Jau kurį laiką programavau, bet dažniausiai „Java“ ir „C #“. Aš niekada neturėjau valdyti atminties. Neseniai pradėjau C ++ programavimą, ir aš šiek tiek supainioti, kai turiu laikyti daiktus ant kamino ir kada juos laikyti krūvoje.

Mano supratimas yra tas, kad kintamieji, kurie yra prieinami labai dažnai, turėtų būti saugomi ant kamino ir objektų, kintamųjų, kurie naudojami retai, ir didelės duomenų struktūros turėtų būti saugomos krūvoje. Ar tai teisinga, ar aš neteisingai?

120
01 марта '09 в 8:32 2009-03-01 08:32 Aleksandras yra nustatytas kovo 01'09, 8:32 2009-03-01 08:32
@ 10 atsakymų

Ne, skirtumas tarp kamino ir krūvos nėra našumas. Gyvenimo trukmė: bet koks vietinis kintamasis funkcijos viduje (viskas, ką nesate Malloc () arba naujas) gyvena ant kamino. Jis išnyksta, kai grįšite iš funkcijos. Jei norite kažką gyventi ilgiau nei funkcija, kuri ją paskelbė, turite ją paskirstyti krūvoje.

 class Thingy; Thingy* foo( ) { int a; // this int lives on the stack Thingy B; // this thingy lives on the stack and will be deleted when we return from foo Thingy *pointerToB =  // this points to an address on the stack Thingy *pointerToC = new Thingy(); // this makes a Thingy on the heap. // pointerToC contains its address. // this is safe: C lives on the heap and outlives foo(). // Whoever you pass this to must remember to delete it! return pointerToC; // this is NOT SAFE: B lives on the stack and will be deleted when foo() returns. // whoever uses this returned pointer will probably cause a crash! return pointerToB; } 

Norėdami geriau suprasti, kas yra kamino, ateikite į jį iš kito galo - užuot stengdamiesi suprasti, ką kainuoja aukšto lygio kalba, ieškokite „skambučių kamino“ ir „skambučio“ ir pažiūrėkite, ką mašina tikrai yra. veikia, kai skambinate funkcijai. Kompiuterio atmintis yra tik adresų serija; krūva ir krūva yra kompiliatoriaus išradimai.

238
01 марта '09 в 8:47 2009-03-01 08:47 atsakymą pateikė „ Crashworks“ kovo 1 d., 09:47, 2009-03-01 08:47

Sakyčiau:

Jei norite, išsaugokite jį ant kamino.

Jei reikia, laikykite jį krūvoje.

Todėl rinkitės kamino kamino. Keletas galimų priežasčių, kodėl negalite kažką laikyti krūvoje, yra šios:

  • Tai per didelė - daugiapakopėms programoms 32 bitų OS sistemoje yra mažas ir fiksuotas (bent jau srauto kūrimo laikas) dydis (paprastai yra tik keli megabaitai. Tai reiškia, kad galite sukurti kelis siūlus, nenaudodami adreso vietos. 64-bitų programų arba vienos srieginės („Linux“) programos nėra rimta problema. 32 bitų „Linux“ vienakryptyje programoje paprastai naudojamos dinaminės kaminai, kurie gali toliau augti, kol pasiekia krūvos viršūnę.
  • Jūs turite prieiti prie jo ne iš šaltinio kamino - tai yra pagrindinė priežastis.

Su protingais kompiliatoriais galima surinkti netinkamo dydžio objektus į krūvą (dažniausiai matricos, kurių dydis nežinomas kompiliavimo metu).

40
01 марта '09 в 11:11 2009-03-01 11:11 atsakymą pateikė MarkR kovo 1 d. , 09:11, 2009-03-01 11:11

Tai yra subtilesnis nei kiti atsakymai. Nėra absoliučio atotrūkio tarp duomenų, esančių krūvoje, ir duomenų, esančių krūvoje, remiantis tuo, kaip skelbiate. Pavyzdžiui:

 std::vector<int> v(10); 

Į funkciją, kuri skelbia vector (dinaminę masyvą) iš dešimties sveikų skaičių kauke. Tačiau vector valdoma saugykla nėra kamino.

Ir, tačiau (pagal kitus atsakymus), šio kapinyno gyvavimo trukmę riboja pačios vector gyvavimo trukmė, kuri yra pagrįsta čia, todėl nesvarbu, kaip ji įgyvendinama - mes galime tik tai laikyti kamino objektais, turinčiais semantinių vertybių.

Ne taip Tarkime, kad ši funkcija yra:

 void GetSomeNumbers(std::vector<int>  { std::vector<int> v(10); // fill v with numbers result.swap(v); } 

Taigi, kažkas su swap funkcija (ir bet kokio tipo sudėtinė vertė turėtų būti tokia) gali būti kaip pakartotinai įterpiama nuoroda į kai kuriuos duomenų kaupimo duomenis sistemoje, kuri garantuoja vienintelį šių duomenų savininką.

Todėl šiuolaikinis C ++ metodas niekada neišsaugo krūvos duomenų adreso vietinio rodyklės tuščiuose kintamuosiuose. Visi krūvos paskirstymai turi būti paslėpti klasėse.

Jei tai padarysite, galite pagalvoti apie visus savo programos kintamuosius, lyg jie būtų paprasti vertės tipai, ir pamiršti apie krūvą (išskyrus atvejus, kai parašysite naują pakuotės klasės klasę tam tikriems krūvos duomenims, kurie turėtų būti neįprastas).

Jums reikia tiesiog išsaugoti vieną specialią žinių dalį, kuri padės jums optimizuoti: jei įmanoma, vietoj to, kad priskirtumėte vieną kintamąjį kitam:

 a = b; 

juos pakeisti taip:

 a.swap(b); 

nes ji yra daug greičiau ir nesukuria išimčių. Vienintelis reikalavimas yra tas, kad jums nereikia b ir toliau turėti tą pačią vertę (vietoj to ji gaus a , kuri bus padalyta į a = b ).

Trūkumas yra tas, kad šis metodas verčia jus grąžinti reikšmes iš funkcijų per išvesties parametrus, o ne faktinę grąžinimo vertę. Bet jie pataiso ją C ++ 0x iš rvalue nuorodos .

Labiausiai sudėtingose ​​situacijose šią idėją shared_ptr į bendrą kraštutinumą ir naudokite pažangių rodyklių klasę, pvz., shared_ptr , kuris jau yra tr1. (Nors norėčiau pasakyti, kad, jei jums atrodo, jūs galėjote peržengti standartinį C ++ saldaus tašką.)

24
01 марта '09 в 12:56 2009-03-01 12:56 atsakymą pateikė Daniel Earwicker, kovo 01'09 , 12:56, 2009-03-01 12:56

Jūs taip pat išsaugotumėte elementą į krūvą, jei jis bus naudojamas už funkcijos, kurioje jis buvo sukurtas, ribų. Vienas idiomas, naudojamas su kamino objektais, yra vadinamas RAII - tai reiškia, kad naudojant kamino pagrindą objektas naudojamas kaip šaltinis, kai objektas sunaikinamas, išteklius bus išvalytas. Stack-based objektai yra lengviau stebimi, kai galite mesti išimtis - jums nereikia nerimauti dėl objekto ištrynimo išimties tvarkyklėje. Štai kodėl šiuolaikiniuose „C ++“ dažniausiai nenaudojamos žaliavos, naudosite pažangų rodyklę, kuri gali būti sukrauti paketą, skirtą neapdorotam rodikliui į objektą su krūva.

6
01 марта '09 в 8:49 2009-03-01 08:49 atsakymas pateiktas 1800 INFORMACIJA Kovo 01'09, 8:49 2009-03-01 08:49

Jei norite pridėti kitų atsakymų, tai taip pat gali būti susiję su našumu, bent jau šiek tiek. Ne tai, kad tai nerimaujate, jei tai jums netaikoma, bet:

Daužų paskirstymui reikia ieškoti atminties sekimo bloko, kuris nėra pastovaus laiko operacija (ir trunka kelis ciklus ir viršutines). Tai gali sulėtėti, nes atminties fragmentacija ir (arba) artėja prie 100% adreso vietos. Kita vertus, stekų paskirstymas yra nuolatinės, dažniausiai „laisvos“ operacijos.

Kitas dalykas, kurį reikia apsvarstyti (vėlgi, tikrai svarbu, jei tai tampa problema) yra tai, kad kamino dydis paprastai yra fiksuotas ir gali būti daug mažesnis už krūvos dydį. Todėl, jei pasirinksite didelius objektus ar daug mažų objektų, tikriausiai norite naudoti krūva; jei pritrūksta kamino vietos, vykdymo laikas bus išimtis. Tai paprastai nėra didelė problema, bet dar vienas dalykas, kurį reikia apsvarstyti.

5
01 марта '09 в 10:46 2009-03-01 10:46 atsakymas duotas Nick kovo 01'09, 10:46 2009-03-01 10:46

Srautas yra efektyvesnis ir lengviau valdomas duomenų srityje.

Bet krūva turėtų būti naudojama kažkam didesnei nei keliems kilobaitams (tai lengva C + +, tiesiog sukurkite boost::scoped_ptr ant kamino, kad laikytumėte rodiklį į priskirtą atmintį).

Apsvarstykite rekursinį algoritmą, kuris ir toliau vadina save. Labai sunku apriboti ir atspėti bendrą krūvos panaudojimą! Jei krūvos paskirstytojas ( malloc() arba new ) gali nukreipti į neaktyviąją atmintį, sugrįžęs į NULL arba throw .

Šaltinis : Linux branduolys, kurio krūva neviršija 8 KB!

3
28 дек. atsakymas duotas unixman83 28 dec. 2011-12-28 02:16 '12 at 2:16 2011-12-28 02:16

Išsamumą galite perskaityti Miro Samek straipsnį apie tai, kaip naudoti krūvą įterptinės programinės įrangos kontekste.

Daug problemų

2
25 янв. Daniel Daranas atsakymas sausio 25 d 2010-01-25 12:22 '10, 12:22, 2010-01-25 12:22

Galimybė pasirinkti, ar paskirti krūvą ar kamino, yra ta, kuri yra sukurta jums, priklausomai nuo to, kaip paskirstomas kintamasis. Jei dinamiškai skiriate „naują“ skambutį, pasirinksite iš krūvos. Jei pasirenkate kažką kaip pasaulinį kintamąjį arba kaip parametrą funkcijoje, jis priskiriamas kaminai.

1
01 марта '09 в 8:48 2009-03-01 08:48 atsakymą pateikė Robas Lachlanas kovo 30 d. 08:48 2009-03-01 08:48

Tai tikriausiai buvo gana gerai atsakyta. Norėčiau nukreipti jus į kitą straipsnių seriją, kad gautumėte gilesnį supratimą apie žemo lygio detales. Alex Darby turi keletą straipsnių, kuriuose jis vadovauja jums derinant. Čia yra 3 dalis apie kaminą. http://www.altdevblogaday.com/2011/12/14/cc-low-level-curriculum-part-3-the-stack/

0
21 июля '12 в 13:41 2012-07-21 13:41 atsakymą pateikė „ hAcKnRoCk“ liepos 21 d., 12 val.

Mano nuomone, yra du lemiami veiksniai.

 1) Scope of variable 2) Performance. 

Daugeliu atvejų norėčiau naudoti kamino, bet jei jums reikia prieigos prie išvaizdos kintamojo, galite naudoti krūva.

Norėdami pagerinti našumą naudojant krūvą, taip pat galite naudoti funkcionalumą kuriant blokų bloką, kuris gali padėti jums pasiekti našumą, o ne paskirstyti kiekvieną kintamąjį skirtingose ​​atminties vietose.

0
01 марта '09 в 12:15 2009-03-01 12:15 atsakymas pateikiamas ir kovo 1 d. 09 val. 12:15 2009-03-01 12:15

Žr. Kitus klausimus „ etikečių arba Užduoti klausimą