DateAuthorAudience
P1331R22019-07-15CJJohnsonCoreWorkingGroup(CWG),previouslyEvolutionWorkingGroup(EWG)
Permittingtrivialdefaultinitializationinconstexprcontexts
UpdatesoverRevision1
UpdatedwordingbasedonfeedbackfromJens
UpdatesoverRevision0
Revision0passedtheEvolutionWorkingGroupstrawpollandwasforwardedtoCoreWorkingGroupforinclusioninC++2a
SFFNASA613520
Mergedcontentfrom"Openquestions"sectioninto"Avoidingundefinedbehavior"sectionandremovedthe"Openquestions"sectionastherearenomoreopenquestionsAddedwordingMinoredits
Introduction
Thispaperproposespermittingdefaultinitializationfortriviallydefaultconstructibletypesinconstexprcontextswhilecontinuingtodisallowtheinvocationofundefinedbehavior.Inshort,solongasuninitializedvaluesarenotreadfrom,suchstatesshouldbepermittedinconstexprinbothheapandstackallocatedscenarios.
Prerequisite
LetthebelowNontrivialTypeandTrivialTypetypedefinitionsbeimportedandvisibleforallfollowingexamplecodesnippets.
structNontrivialType{boolval=false;
};
structTrivialType{boolval;
};
JustificationasofC++17
Fortypeswithnontrivialdefaultconstructors,defaultinitializationisdefinedascallingthedefaultconstructor.Thisbehaviorisconsistentacrossruntimeandconstexprcontexts(assumingthedefaultconstructorismarkedasordefaultedasconstexpr).Unfortunately,thisguaranteedoesnotgenericallyapplyacrossthelanguage.Fortypeswithtrivialdefaultconstructors,defaultinitializationdoespileinconstexpr.Thisesapainpointwhenwritinggenericcode.Someconstexprfunctiontemplatesthatarewelldefinedfortypeswithuser-definedconstexprdefaultconstructorswillfailpilewheninstantiatedwith,forexample,anyofthefundamentalintegertypesprovidedbythelanguage.
Thebelowcodeexample,Example1,showshowthisinconsistencycannegativelyaffectcodethatonewouldexpecttobeconsistentacrosstemplateinstantiations.Ifthisproposalisadopted,allfourbelowcallsites,insteadofjustthefirstthree,wouldbevalidpilecoveringthefullmatrixofruntime/constexprbytrivially/nontriviallydefaultconstructible.
namespaceExample1{
templateconstexprTf(constT&other){
Tt;t=other;returnt;}
//defaultinitialization
//Thesethreepileautonontrivial_rt=f(NontrivialType{});autotrivial_rt=f(TrivialType{});constexprautonontrivial_ct=f(NontrivialType{});
//AsofC++17,thisfailspilemeaning`Example1::f(constT&)`isnot//genericconstexprautotrivial_ct=f(TrivialType{});
}//namespaceExample1
Note:nontrivial_rtisconstantinitializedsinceExample1::f(constNontrivialType&)isvalidinconstexpr.Asabonus,bymakingExample1::f(constTrivialType&)validinconstexpr,trivial_rtwillalsobegivenconstantinitialization.
JustificationforC++2a
Inadditiontotheunexpectedlyinconsistentbehaviordemonstratedabove,thepresenceofP0784[1]inC++2astrengthenstheneedforthisproposedchange.Trivialdefaultinitializationisallowed,butonlyforheapallocatedobjects.Thisproposalwouldsimplyfixthe"bug"disallowingthatsamebehaviorforstackallocatedobjects.
Thebelowexamples,Example2andExample3,showside-by-sidewhatshouldbesemanticallyequivalentfunctions.ThecurrentC++2adraftstandard,withtheadoptionofP0784,wouldpermit,inconstexpr,thefunctiondefinitionsthatuseheapallocationbutnotthefunctiondefinitionsthatusestackallocation.Thisproposal,ifadoptedwithP0784,wouldresultinallfourbelowcallsitesbeingvalid.
namespaceExample2{
templateconstexprTf1(constT&other){
auto*t=newT;*t=other;Tout=*t;deletet;returnout;}
//defaultinitialization
templateconstexprTf2(constT&other){
Tt;t=other;Tout=t;returnout;
//defaultinitialization
}
//pilesconstexprautotrivial_ct_h=f1(TrivialType{});
//Failspilemeaning`Example2::f1(constT&)`and//`Example2::f2(constT&)`areobservablydifferentconstexprautotrivial_ct_s=f2(TrivialType{});
}//namespaceExample2
namespaceExample3{
templateconstexprTf1(constT&other){
auto*t=newT[1];t[0]=other;Tout=t[0];delete[]t;returnout;}
//defaultinitialization
templateconstexprTf2(constT&other){
Tt[1];t[0]=other;Tout=t[0];returnout;}
//defaultinitialization
//pilesconstexprautotrivial_ct_h=f1(TrivialType{});
//Failspilemeaning`Example3::f1(constT&)`and//`Example3::f2(constT&)`areobservablydifferentconstexprautotrivial_ct_s=f2(TrivialType{});
}//namespaceExample3
Avoidingundefinedbehavior
Asalways,undefinedbehaviorcannotbeinvokedinconstexpr.Inordertoallowtrivialdefaultinitialization,somemechanismmustbeinplacethatpreventsreadinguninitializedvalues.Thatmechanismshouldcontinuetopilationfailure;however,insteadoftheoverlyrestrictivecurrentbehavior(failingpileatthepointofinitialization),pilationshouldonlyfailatthepointincodewheretheuninitializedreadtakesplace.
Thisshouldnotbedifficultpilerdeveloperstoimplementnorshoulditcausemuchifpiletimeoverhead.Thestepsrequiredaresimilartodetectingreadsofout-of-lifetimevariables,somethingthatpilersalreadyimplementforconstantevaluation.[2]
Thatsaid,readinguninitializedinstancesofunsignedcharatruntimeisnotundefined.Fornow,suchbehaviorshallremainnon-constant.FromRichardSmith:
Themostreasonablethingwouldbetosaythat(intheshorttermatleast),readingthevalueofanuninitializedobjectisnon-constantregardlessofitstype.Wecanrevisitthatdecisionifwefindausecase,butgoingintheotherdirectionwouldbemoreproblematicduetobeingapotentiallybreakingchange.[3]
Furtherjustification:On"Constexprallthethings!
" absl::InlinedVector<
T,N,A>isastd::vector<
T,A>-liketypethattakesadvantageoftheSmallSizeOptimization(SSO).SSOisimplementedbyincludingabufferinsidethetypetoavoidallocationforsmallinstances.Asanoptimization,unusedbytesintheinlinedbufferareleftuninitialized."Don'tpayforwhatyoudon'tuse,"astheysay. InthespiritofP0784[1],ifInlinedVectorweretobemadeavailableinconstexpr,thebehaviorshouldbeconsistentwiththebehaviorofruntimeinstances.TheunusedinlinedbytesshouldbeabletobeleftuninitializedsothatimplementersmaybeabletoexposeidentaluninitializedreadsthroughconstexprevaluationandUBSan. Additionally,fromamaintenceperspective,nothavingtoforktheimplementationtohandleconstexprismuchappreciated. Wording Toensurereadinguninitializedinstancesofunsignedcharremainsnon-constant,under[expr.const],addanewbullettop4betweentheexisting(4.8)and(4.9): [...] (4.8)-anlvalue-to-rvalueconversionthatisappliedtoaglvaluethatreferstoa non-activememberofaunionorasubobjectthereof; +(
4.X)-anlvalue-to-rvalueconversionthatisappliedtoanobjectwithindeterminate + value([basic.indet]); (4.9)-aninvocationofanimplicitly-definedcopy/moveconstructororcopy/moveassignment operatorforaunionwhoseactivemember(ifany)ismutable,unlessthelifetimeof theunionobjectbeganwithintheevaluationofe; [...] Under[dcl.constexpr],removethelastconditionfrom(3.4.4)andupdatetheexample: [...] (3.4.4)-adefinitionofavariableofnon-literaltypeorofstaticorthreadstorage - durationorforwhichnoinitializationisperformed. + duration. [...] [...]constexprintuninit(){-inta;-returna;+struct{inta;}s;+returns.a;}[...] //error:variableisuninitialized//error:uninitializedreadofs.a Alsounder[dcl.constexpr],remove(4.4): [...] (4.3)-eitheritsfunction-bodyshallbe=default,orpound-statementofits function-bodyshallsatisfytherequirementsforafunction-bodyofaconstexprfunction; -(4.4)-everynon-variantnon-staticdatamemberandbaseclasssubobjectshallbeinitialized - ([class.base.init]); (4.5)-iftheclassisaunionhavingvariantmembers([class.union]),exactlyoneofthemshall beinitialized; [...] Under[cpp.predefined],update__cpp_constexprintable17under(1.8): |Macroname |Value| |----------------------------|---------| [...] |__cpp_conditional_explicit|201806L| -|__cpp_constexpr |201603L| +|__cpp_constexpr |201907L| |__cpp_coroutines |201902L| [...] References [1]P0784:Moreconstexprcontainers[2]PersonalcorrespondencewithRichardSmithaboutthisproposal[3]CommentbyRichardSmithin[RFC]P1331:Permittingtrivialdefaultinitializationinconstexprcontexts
" absl::InlinedVector<
T,N,A>isastd::vector<
T,A>-liketypethattakesadvantageoftheSmallSizeOptimization(SSO).SSOisimplementedbyincludingabufferinsidethetypetoavoidallocationforsmallinstances.Asanoptimization,unusedbytesintheinlinedbufferareleftuninitialized."Don'tpayforwhatyoudon'tuse,"astheysay. InthespiritofP0784[1],ifInlinedVectorweretobemadeavailableinconstexpr,thebehaviorshouldbeconsistentwiththebehaviorofruntimeinstances.TheunusedinlinedbytesshouldbeabletobeleftuninitializedsothatimplementersmaybeabletoexposeidentaluninitializedreadsthroughconstexprevaluationandUBSan. Additionally,fromamaintenceperspective,nothavingtoforktheimplementationtohandleconstexprismuchappreciated. Wording Toensurereadinguninitializedinstancesofunsignedcharremainsnon-constant,under[expr.const],addanewbullettop4betweentheexisting(4.8)and(4.9): [...] (4.8)-anlvalue-to-rvalueconversionthatisappliedtoaglvaluethatreferstoa non-activememberofaunionorasubobjectthereof; +(
4.X)-anlvalue-to-rvalueconversionthatisappliedtoanobjectwithindeterminate + value([basic.indet]); (4.9)-aninvocationofanimplicitly-definedcopy/moveconstructororcopy/moveassignment operatorforaunionwhoseactivemember(ifany)ismutable,unlessthelifetimeof theunionobjectbeganwithintheevaluationofe; [...] Under[dcl.constexpr],removethelastconditionfrom(3.4.4)andupdatetheexample: [...] (3.4.4)-adefinitionofavariableofnon-literaltypeorofstaticorthreadstorage - durationorforwhichnoinitializationisperformed. + duration. [...] [...]constexprintuninit(){-inta;-returna;+struct{inta;}s;+returns.a;}[...] //error:variableisuninitialized//error:uninitializedreadofs.a Alsounder[dcl.constexpr],remove(4.4): [...] (4.3)-eitheritsfunction-bodyshallbe=default,orpound-statementofits function-bodyshallsatisfytherequirementsforafunction-bodyofaconstexprfunction; -(4.4)-everynon-variantnon-staticdatamemberandbaseclasssubobjectshallbeinitialized - ([class.base.init]); (4.5)-iftheclassisaunionhavingvariantmembers([class.union]),exactlyoneofthemshall beinitialized; [...] Under[cpp.predefined],update__cpp_constexprintable17under(1.8): |Macroname |Value| |----------------------------|---------| [...] |__cpp_conditional_explicit|201806L| -|__cpp_constexpr |201603L| +|__cpp_constexpr |201907L| |__cpp_coroutines |201902L| [...] References [1]P0784:Moreconstexprcontainers[2]PersonalcorrespondencewithRichardSmithaboutthisproposal[3]CommentbyRichardSmithin[RFC]P1331:Permittingtrivialdefaultinitializationinconstexprcontexts
声明:
该资讯来自于互联网网友发布,如有侵犯您的权益请联系我们。