C ++ 17:由编译器(静态存储持续时间)const引用创建的临时对象(和存储)结合可修改?

问题描述 投票:2回答:1

让我们编译下面的顶级声明

const int& ri = 5;

clang++。与-std=c++14和它下面放置临时对象(和代表参考指针)插入.rodata部分:

        .type   _ZGR2ri_,@object        # @_ZGR2ri_
        .section        .rodata,"a",@progbits
        .p2align        2
_ZGR2ri_:
        .long   5                       # 0x5
        .size   _ZGR2ri_, 4

        .type   ri,@object              # @ri
        .globl  ri
        .p2align        3
ri:
        .quad   _ZGR2ri_
        .size   ri, 8

但是,如果我们改变标准版本-std=c++17(或以上),该对象将被放置到.data部(指针仍处于.rodata,虽然):

        .type   _ZGR2ri_,@object        # @_ZGR2ri_
        .data
        .p2align        2
_ZGR2ri_:
        .long   5                       # 0x5
        .size   _ZGR2ri_, 4

        .type   ri,@object              # @ri
        .section        .rodata,"a",@progbits
        .globl  ri
        .p2align        3
ri:
        .quad   _ZGR2ri_
        .size   ri, 8

什么是这种行为的原因是什么?它是一个错误吗?它仍然由它的初始值ri替换同恩5的所有使用这一事实表明,这是一个错误。

我的假设是,在[dcl.init.ref]/5.2

如果转换后的初始值设定为prvalue,它的类型T4被调整到输入“CV1 T4”([conv.qual])并施加临时物化转换。

它天真丢弃(或者更确切地说,不添加)从(到)prvalue类型cv1限定符。

有趣的是,如果更换的非参考相关的一个prvalue的初始化表达式,但敞篷车型

const int& ri = 5.0;

它开始再次把目标与价值5.rodata部分。

是否有,现在需要这样的可变性的标准什么?换一种说法:

  • 它由ri修改指定由符合代码的对象? (显然包括UB代码可以试着去改变它,并且不需要编译器作出努力,以允许)
  • 是,对象的存储通过符合代码,通过重新使用它来创建尺寸的另一个目的不大于所述临时“别名”的尺寸更大的修改(“参考文献是别名”)由是risizeof (int)
c++ const language-lawyer c++17 temporary-objects
1个回答
1
投票

让我们分析

const int& ri = 5;

从C ++草案:引用的初始化[dcl.init.ref]/5

键入“CV1 T1”的引用由类型“CV2 T2”如下的表达式进行初始化:

这里CV1 = const,T1 = int,CV2 = “”,T2 = int

跳过unapplicable条款,我们来到这里[dcl.init.ref]/5.3

否则,如果初始化表达式(5.3.1)是一个rvalue(但不是一个位域)(...)和“CV1 T1”是参考兼容“CV2 T2”,或(...),那么初始化表达式(...)的值被称为转换的初始值设定。

转换后的初始值设定为5一个prvalue。

如果转换后的初始值设定为prvalue,它的类型T4被调整到输入“CV1 T4”([conv.qual])和临时物化转换([conv.rval])被施加。在任何情况下,引用绑定到所得glvalue(...)

KV1总胆固醇= kazhsvpoi

所以创建类型const int的对象和引用绑定到它。

“临时物化转换”是新概念,在这里解释const int

类型T的prvalue可以转换为类型T的x值该转化通过评估与该临时对象作为其结果对象中的prvalue初始化从prvalue类型T的临时对象([class.temporary]),并产生一个x值表示的临时对象。牛逼应是一个完整的类型。

因此,我们有一个转换prvalue - > x值 - >左值。

临时的寿命在[conv.rval]描述:

临时对象到该参考是结合或(...)持续基准的寿命,如果glvalue到该参考结合通过以下之一得到:

(6.1)的临时物化转化率([conv.rval]),(...)

因此,这种情况和临时的一生“持续引用的一生”。

[class.temporary]/6

程序可以通过重新使用该对象占据存储结束任何对象的生命周期

但不是每一个对象存储可以采用这种方式:[basic.life]/5

创建与静态,螺纹,或自动存储时间常量完整的对象占用,或者这样的const对象常常占据其生命周期结束之前,不确定的行为结果的存储中的存储内的新对象。

存储时间在这里被定义[basic.memobj]/10

的存储持续时间是定义包含该对象的存储的最小潜在寿命的对象的属性。的存储持续时间由用于创建对象的构建物来确定,可以是以下之一:(1.1)的静态存储持续时间(1.2)线程存储时限(1.3)自动存储持续时间(1.4)动态存储持续时间2静态,线程和自动存储的持续时间与由声明引入([basic.def])和隐式创建由实现对象相关联。

但随后的文字只提到变量,而不是对象。我没有看到一个临时的存储持续时间定义在哪里!

编辑:@LanguageLawyer点我到这个核心缺陷:

[basic.stc]

参考到15.2 [class.temporary]的表观的意图是,临时其寿命延长到是一个参考的与那些存储的持续时间被认为还具有存储持续时间中的一个。

(...)临时对象(也有15.2 class.temporary]第5段)的寿命延长的规范不说的存储时间任何事情。此外,没有在任何有关临时的存储持续时间,其寿命没有延长这些位置的说。

所以,的确有规范缺少的一部分;通过实施创建这些对象的生存期不明确的规定。在C ++一生的规格是困难的,因为你可以从许多增加的寿命,工会,子对象的规格看,并在最近的标准“嵌套”;这些新条款甚至适用于不使用新的C ++功能代码,那是ARM的时间用来支撑(但不能很好的描述)在预标准代码,如代码所做的无非改变更多“有源部件”联合的。

如果说明书被解释为DR要求的方式是意图,1634. Temporary storage duration临时值为5将具有静态存储持续时间的寿命;它的内存将不具有法律修改和可放置在只读部分。

(另一种解决方案:该委员会也可弥补的临时特定存储类)。

© www.soinside.com 2019 - 2024. All rights reserved.