Ką aš = aš +1; teisėtas C + + 17?

Prieš pradėdami rėkti neapibrėžto elgesio, tai aiškiai nurodyta N4659 (C ++ 17)

  i = i++ + 1; // the value of i is incremented 

Tačiau, N3337 (C ++ 11)

  i = i++ + 1; // the behavior is undefined 

Kas pasikeitė?

Iš to, ką galiu sudaryti, iš [N4659 basic.exec]

Išskyrus atvejus, kai pažymėta, atskirų operatorių operandų vertinimas ir atskirų išraiškų išraiška neturi reikšmės. [...] Prieš skaičiuojant operatoriaus rezultatą, skaičiuojami operando operatoriaus vertės. Jei šalutinis poveikis atminties ląstelėje nepriklauso nuo kito šalutinio poveikio toje pačioje atminties ląstelėje arba apskaičiuojant vertę naudojant bet kurio objekto vertę toje pačioje atminties vietoje, ir jie nėra potencialiai lygiagretūs, elgesys yra neapibrėžtas.

Jei vertė yra nustatyta [N4659 basic.type]

Trivialiai nukopijuotiems tipams reikšmių atvaizdavimas yra objektų reprezentacijoje esančių bitų rinkinys, kuris apibrėžia vertę, kuri yra vienas atskiras įgyvendinimo specifinių reikšmių rinkinio elementas.

Nuo [N3337 basic.exec]

Išskyrus atvejus, kai pažymėta, atskirų operatorių operandų vertinimas ir atskirų išraiškų išraiška neturi reikšmės. [...] Prieš skaičiuojant operatoriaus rezultatą, skaičiuojami operando operatoriaus vertės. Jei šalutinis poveikis skalaro objektui neturi jokio kito šalutinio poveikio to paties skalaro objekto atžvilgiu arba apskaičiuojant vertę naudojant to paties skalaro objekto vertę, elgesys yra neapibrėžtas.

Panašiai reikšmė yra apibrėžta [N3337 basic.type]

Trivialiai nukopijuotiems tipams reikšmių atvaizdavimas yra objektų reprezentacijoje esančių bitų rinkinys, kuris apibrėžia vertę, kuri yra vienas atskiras įgyvendinimo specifinių reikšmių rinkinio elementas.

Jie yra identiški, išskyrus tai, kad paminėta sutapimas, nesvarbu, ir naudojant atminties vietą vietoj skalaro objekto, kur

Šių tipų aritmetiniai tipai, skaičiavimo tipai, rodyklės tipai, rodyklės į narių tipus, std::nullptr_t ir cv kvalifikacijos versijos yra bendrai vadinami skalariniais tipais.

Tai neturi įtakos pavyzdžiui.

Nuo [N4659 expr.ass]

Visų grupių priskyrimo operatorius (=) ir junginių priskyrimo operatoriai iš dešinės į kairę. Jie visi reikalauja modifikuojamo lvalue, nes jų kairieji operandai ir grąžina lvalue, nurodydami kairįjį operandą. Visais atvejais rezultatas yra bitų laukas, jei kairysis operandas yra bitų laukas. Visais atvejais priskyrimas užsakomas apskaičiuojant dešiniųjų ir kairiųjų operandų vertę ir prieš apskaičiuojant priskyrimo išraiška. Teisė operanda seka prieš kairįjį operandą.

Nuo [N3337 expr.ass]

Visų grupių priskyrimo operatorius (=) ir junginių priskyrimo operatoriai iš dešinės į kairę. Jie visi reikalauja modifikuojamo lvalue, nes jų kairieji operandai ir grąžina lvalue, nurodydami kairįjį operandą. Visais atvejais rezultatas yra bitų laukas, jei kairysis operandas yra bitų laukas. Visais atvejais priskyrimas atliekamas apskaičiuojant dešiniųjų ir kairiųjų operandų vertę ir prieš apskaičiuojant priskyrimo išraiška.

Vienintelis skirtumas yra tas, kad paskutiniame sakinyje N3337 nėra.

Tačiau paskutinis sakinys neturėtų turėti jokios reikšmės, nes kairysis operandas i nėra nei „kitas šalutinis poveikis“, nei „to paties skalaro objekto reikšmė“, nes id-išraiška yra lvalue.

138
07 дек. nustatė Passer Iki 07 d. 2017-12-07 22:16 '17, 10:16 pm 2017-12-07 22:16
@ 3 atsakymai

C ++ 11, „priskyrimo“ veiksmas, ty LHS modifikacijos šalutinis poveikis, seka apskaičiuojant dešiniojo operando vertę. Atkreipkite dėmesį, kad tai yra santykinai „silpna“ garantija: ji sukuria seką tik atsižvelgiant į RHS sąnaudų apskaičiavimą. Jame nieko nekalbama apie šalutinį poveikį, kuris gali būti RHS, nes šalutinių poveikių atsiradimas nėra sąnaudų skaičiavimo dalis. C ++ 11 reikalavimai nenustato santykinio užsakymo tarp pasiskirstymo akto ir bet kokio šalutinio RHS poveikio. Tai sukuria UB potencialą.

Šiuo atveju vienintelė viltis yra bet kokios papildomos garantijos, kurias teikia RHS naudotojai. Jei RHS naudojo prefiksą ++ , sekos savybės, būdingos prefiksui ++ , išsaugotų dieną šiame pavyzdyje. Bet postfix ++ yra visiškai kitokia istorija: ji nesuteikia tokių garantijų. C ++ 11 šiame pavyzdyje šalutinis poveikis = ir postfix ++ neturi įtakos tarpusavio santykiams. Ir tai yra UB.

C ++ 17 papildoma nuostata pridedama prie priskyrimo ataskaitos specifikacijos:

Teisingas operandas sekvenuojamas prieš kairįjį operandą.

Kartu su pirmiau minėta, tai suteikia labai tvirtą garantiją. Jis atlieka viską, kas vyksta RHS (įskaitant bet kokį šalutinį poveikį) prieš tai, kas vyksta LHS. Kadangi faktinis priskyrimas seka po LHS (ir RHS), šis papildomas sekimas visiškai išskiria priskyrimo veiksmus nuo bet kokių šalutinių poveikių, esančių RHS. Šis stipresnis užsakymas pašalina aukščiau nurodytą UB.

(Atnaujinta, kad būtų atsižvelgta į @John Bollinger komentarus.)

105
07 дек. Atsakymas duotas AnT gruodžio 7 d. 2017-12-07 22:31 '17, 10:31 pm 2017-12-07 22:31

Jūs nustatėte naują pasiūlymą.

Teisingas operandas sekvenuojamas prieš kairįjį operandą.

ir teisingai nustatėte, kad kairiojo operando, kaip lvalue, įvertinimas nėra svarbus. Tačiau sekos yra anksčiau apibrėžtos kaip tranzitiniai santykiai. Taigi, prieš priskyrimą, taip pat sekvenuojamas visas dešinysis operandas (įskaitant post-prieaugį). C ++ 11 atveju prieš paskirties vietą buvo užsakyta tik dešiniojo operando vertės apskaičiavimas.

27
07 дек. atsakymas pateikiamas 07 val. 2017-12-07 22:31 '17, 10:31 pm 2017-12-07 22:31

Senuose C + + standartuose ir C11, priskyrimo ataskaitos teksto apibrėžimas baigiasi tekstu:

Operatorių vertinimai neturi įtakos.

Faktas, kad operandų šalutiniai poveikiai nėra nuoseklūs ir todėl neapibrėžtas elgesys, jei jie naudoja tą patį kintamąjį.

Šis tekstas buvo paprasčiausiai ištrintas C ++ 11, paliekant jį šiek tiek dviprasmišką. Ar tai UB, ar ne? Tai paaiškinta C ++ 17, kur jie pridėjo:

Teisingas operandas sekvenuojamas prieš kairįjį operandą.


Kaip papildoma pastaba, net senesniuose standartuose, buvo labai aišku, pavyzdžiui, iš C99:

Operandų vertinimo tvarka nenustatyta. Jei bandoma pakeisti priskyrimo ataskaitos rezultatą arba prieigą prie jo po kito sekos taško, elgesys yra neapibrėžtas.

Iš esmės, C11 / C ++ 11, jie ištrynė šį tekstą.

3
11 дек. Atsakymą pateikė Lundin . 2017-12-11 16:02 '17, 16:02 pm 2017-12-11 16:02

Žr. Kitus klausimus apie „ kalbos ir advokato „ žymes arba užduokite klausimą