Kodėl mano programinė įranga nukrenta, kai padidina rodyklę ir ją ištrina?

Kai supratau, kad turėjau didelį nesusipratimą dėl nuorodų, išsprendžiau kai kurias programavimo pratybas. Prašome, kad kas nors galėtų paaiškinti priežastį, kodėl šis kodas yra „C ++“.

 #include <iostream> int main() { int* someInts = new int[5]; someInts[0] = 1; someInts[1] = 1; std::cout << *someInts; someInts++; //This line causes program to crash delete[] someInts; return 0; } 

PS Aš žinau, kad nėra jokios priežasties naudoti „naują“, aš tiesiog pateikiu pavyzdį kaip įmanoma mažesnį.

31
16 дек. Burokėlių rinkinys gruodžio 16 d 2016-12-16 15:08 '16 at 15:08 2016-12-16 15:08
@ 4 atsakymai

Tai iš tikrųjų yra pareiškimas po to, kai pažymite, kad tai sukelia programos gedimą, ir dėl to programa sugenda!

Turite perkelti tą patį žymiklį, kad delete[] kai grįšite iš new[] .

Priešingu atveju programos elgesys yra neapibrėžtas.

81
16 дек. Atsakymas duotas Bathsheba gruodžio 16 d. 2016-12-16 15:09 '16 at 15:09 2016-12-16 15:09

Problema yra ta, kad kai kurie „ someInts++; perkeliate antrojo masyvo elemento adresą į savo delete[] operatorių. Turite perduoti pirmojo (originalo) elemento adresą:

border=0
 int* someInts = new int[5]; int* originalInts = someInts; // points to the first element someInts[0] = 1; someInts[1] = 1; std::cout << *someInts; someInts++; // points at the second element now delete[] originalInts; 
34
16 дек. Atsakymą pateikė vartotojo1593881 16 gruodis. 2016-12-16 15:33 '16 at 15:33 2016-12-16 15:33

Nesikreipiant į konkretaus įgyvendinimo specifiką, intuityvioji priežastis, dėl kurios nepavyko išspręsti, gali būti paaiškinta paprasčiausiai, nes delete[] turėtų daryti:

Sunaikina masyvą, sukurtą new[]

Jūs nurodote delete[] rodyklę masyvui. Be to, jis turi atleisti paskirtą atmintį, kad po to išsaugotų šio masyvo turinį.

Kaip platintojas žino, ką daryti? Jis naudoja žymiklį, kurį nurodėte kaip raktą, norėdami ieškoti duomenų struktūros, kurioje yra pasirinktos bloko apskaitos informacija. Kažkur yra struktūra, kurioje saugomi rodikliai tarp anksčiau priskirtų blokų ir susijusios apskaitos operacijos.

Jei pageidaujate, kad ši paieška gautų šiek tiek klaidos pranešimą, jei rodyklė, kurią perdavėte delete [] nebuvo grąžinta pagal new[] , tačiau šiame standarte nėra nieko.

Taigi, galbūt su žymekliu, kuris anksčiau nebuvo priskirtas new[] , delete[] galiausiai nėra nuosekli apskaitos struktūra. Laidai susikerta. Yra avarijos.

Arba galbūt norėtumėte delete[] pasakyti: „Ei, atrodo, kad šis žymeklis rodo, kas yra anksčiau pasirinktoje srityje. Leiskite grįžti ir rasti žymeklį, kurį sugrįžau, kai pasirinksiu šį regioną ir naudokite jį ieškoti apskaitos informacijos “, tačiau standarte nėra tokio reikalavimo:

Antrojoje (masyvo) formoje išraiška turi būti nulinio rodiklio reikšmė arba rodyklės vertė, gauta iš naujos išraiškos masyvo formos. Jei išraiška yra kažkas , įskaitant, jei tai rodyklė, gauta iš naujosios išraiškos ne masyvo formos, elgesys yra neapibrėžtas . [mano akcentas]

Šiuo atveju jums pasisekė, nes nustatėte, kad tuoj pat padarė kažką neteisingo.

PS: Tai yra rankinis paaiškinimas.

19
16 дек. Sinan Ünür atsakymas 16 d 2016-12-16 18:26 '16 at 18:26 pm 2016-12-16 18:26

Galite padidinti žymiklį bloko viduje ir naudoti šį didėjantį rodiklį, kad galėtumėte pasiekti įvairias bloko dalis, tai yra normalu.

Vis dėlto turite pereiti per „Delete the pointer“, kurį gavote iš „New“. Tai nėra papildoma versija, o ne rodyklė, paskirta kitomis priemonėmis.

Kodėl gerai, atsakymas yra atmetimas, nes tai yra standartas.

Praktinis atsakymas yra tas, kad, norint atlaisvinti atminties bloką, atminties valdytojui reikia informacijos apie bloką. Pavyzdžiui, kur jis prasideda ir baigiasi, ir ar gretimi vienetai yra laisvi (dažniausiai atminties tvarkyklė sujungia gretimus nemokamus gabalus) ir į kurią areną ji priklauso (svarbu blokuoti daugiaukelėje atminties tvarkyklėje).

Ši informacija paprastai saugoma prieš pat skiriamą atmintį. Atminties tvarkyklė atima fiksuotą vertę iš jūsų rodyklės ir ieško paskirstymo metaduomenų struktūros toje vietoje.

Jei išlaikote žymeklį, kuris nenurodo skiriamosios atminties bloko pradžios, tada atminties tvarkyklė bando atlikti atimimą ir perskaityti jo valdymo bloką, tačiau jis baigia skaityti nėra galiojantis valdymo blokas.

Jei esate laimingas, tada kodas greitai nepavyks, jei nesate laimingas, galite gauti subtilų atminties pažeidimą.

9
16 дек. atsakymas duotas plugwash 16 gruodis 2016-12-16 20:24 '16 at 8:24 pm 2016-12-16 20:24