不死对象 ([basic.life]/8):为什么允许引用重新绑定(和 const 修改)?

2024-03-28

“不死”条款

我将 undead 子句称为 C++ 规则,即在对象销毁后,如果在同一地址创建新对象,则有时可以将其视为与旧对象相同的对象。该规则在 C++ 中始终存在,但附加条件发生了一些变化。

我被迫阅读最新的不死条款这个问题 https://stackoverflow.com/q/59239085/963864。修订后的条件Lifetime [基本生活]/8 https://stackoverflow.com/q/59239085/963864 are:

(8.1) 新对象的存储完全覆盖存储 原始对象占据的位置,以及

嗯,呃。不同地址的对象不会是同一个对象。

(8.2) 新对象与原对象类型相同 (忽略顶级简历限定符),以及

再说一次,呃。

(8.4) 原始对象和新对象都不是 可能重叠的子对象([intro.object])。

它不能是基类、经典类(或具有使其地址不唯一的特殊声明的成员)。再说一次,呃。

(8.3) 原始对象既不是一个完整的对象, const 限定的也不是此类对象的子对象,并且

现在这很有趣。被替换的对象不能是:

  • 一个完整的 const 对象
  • 完整 const 对象的一部分

另一方面,被复活的对象可以是:

  1. const 成员子对象
  2. 此类常量成员的子对象
  3. const 对象数组中的元素

常量子对象

所以在我看来所有这些物体x可以复活:

常量成员子对象

struct CI {
  const int x;
};

CI s = { 1 };
new ((void*)&s.x) int(2);
int r = s.x; // OK, 2

const 成员的子对象:

struct T {
  int x;
};

struct CT {
  const T m = { 1 };
};

CT s;
new ((void*)&s.m.x) int (2);
int r = s.m.x;

const 对象数组中的元素:

const int x[1] = { 1 };
new ((void*)&x[0]) int (2);
int r = x[0];

具有 const 和引用成员的类

此外,具有 const 或引用成员的类类型对象似乎也不被禁止;复活的对象仍然被称为x.

具有 const 成员的类:

struct CIM {
  CIM(int i): m(i) {}
  const int m;
};

CIM x(1);
new ((void*)&x) CIM(2);
int r = x.m; // OK, 2

具有参考成员的类:

struct CRM {
  CRM (int &r): m(r) {}
  int &m;
};

int i=1,j=2;
CRM x(i);
new ((void*)&x) CRM(j);
int r = x.m; // OK, 2

问题

  1. 该条款的这种解释正确吗?
  2. 如果是的话,是否还有其他条款禁止这些覆盖操作?
  3. 如果是这样,这是故意的吗?为什么会改变?
  4. 这对代码生成器来说是一个重大改变吗?所有编译器真的都支持吗?他们不是基于 const 成员、数组的 const 元素不可变和引用不可反弹来进行优化吗?
  5. 额外问题:这是否会影响具有足够存储类(当然不是动态创建的对象)和足够初始化的 const 对象的 ROM 能力?

注意:我后来添加了这个奖励,因为在讨论中提到了将常量放入 ROM 中。


如果与对象生命周期相关的标准的所有要求都不在[基本生命周期]中,那将是令人惊讶的。

在您引用的标准段落中,“完整”形容词被无意中添加到“对象”名称中的可能性很小。

在论文中P0137 http://wg21.link/p0137r1,人们可以阅读这个理性(下面@LanguageLawyer评论中引用的论文):

这是允许 std::Optional 等类型包含 const 子对象所必需的;现有的限制是为了允许 ROMability,因此只影响完整的对象。

为了让我们放心,我们可以验证编译器确实遵循字母中的标准措辞:它们对完整的 const 对象执行常量优化,但不对非 const 完整对象的 const 成员子对象执行常量优化:

让我们考虑一下这段代码 https://godbolt.org/z/Kt2Cef:

struct A{const int m;};

void f(const int& a);

auto g(){
    const int x=12;
    f(x);
    return x;
}

auto h(){
    A a{12};
    f(a.m);
    return a.m;
}

当面向 x86_64 时,Clang 和 GCC 都会生成此程序集:

g():                                  # @g()
        push    rax
        mov     dword ptr [rsp + 4], 12
        lea     rdi, [rsp + 4]
        call    f(int const&)
        mov     eax, 12     ;//the return cannot be anything else than 12
        pop     rcx
        ret
h():                                  # @h()
        push    rax
        mov     dword ptr [rsp], 12
        mov     rdi, rsp
        call    f(int const&)
        mov     eax, dword ptr [rsp]  //the content of a.m is returned
        pop     rcx
        ret

返回值存放在寄存器中eax(根据 ABI 规范:System V x86 处理器特定 ABI):

  • 在函数中g编译器可以自由地假设x不能通过调用来更改f因为x是一个完整的 const 对象。所以价值12被直接放置在eax注册为立即值:mov eax, 12.

  • 在函数中h编译器不能随意假设a.m不能通过调用来更改f因为a.m不是完整 const 对象的子对象。所以在致电之后f的价值a.m必须从内存加载到eax : mov eax, dword ptr [rsp].

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

不死对象 ([basic.life]/8):为什么允许引用重新绑定(和 const 修改)? 的相关文章

  • Signalr 在生产服务器中总是陷入长轮询

    当我在服务器中托管应用程序时 它会检查服务器端事件并始终回退到长轮询 服务器托管环境为Windows Server 2012 R1和IIS 7 5 无论如何 我们是否可以解决这个问题 https cloud githubuserconten
  • 在 Xamarin Android 中将图像从 URL 异步加载到 ImageView 中

    我有一个包含多个项目的 ListView 列表中的每个项目都应该有一个与之关联的图像 我创建了一个数组适配器来保存每个列表项并具有我希望加载的图像的 url 我正在尝试使用 Web 请求异步加载图像 并设置图像并在加载后在视图中更新它 但视
  • C++ 求二维数组每一行的最大值

    我已经设法用这个找到我的二维数组的每一行的最小值 void findLowest int A Cm int n int m int min A 0 0 for int i 0 i lt n i for int j 0 j lt m j if
  • 将字符串从非托管代码传递到托管

    我在将字符串从非托管代码传递到托管代码时遇到问题 在我的非托管类中 非托管类 cpp 我有一个来自托管代码的函数指针 TESTCALLBACK FUNCTION testCbFunc TESTCALLBACK FUNCTION 接受一个字符
  • 按字典顺序对整数数组进行排序 C++

    我想按字典顺序对一个大整数数组 例如 100 万个元素 进行排序 Example input 100 21 22 99 1 927 sorted 1 100 21 22 927 99 我用最简单的方法做到了 将所有数字转换为字符串 非常昂贵
  • .Net Core / 控制台应用程序 / 配置 / XML

    我第一次尝试使用新的 ConfigurationBuilder 和选项模式进入 Net Core 库 这里有很多很好的例子 https docs asp net en latest fundamentals configuration ht
  • A* 之间的差异 pA = 新 A;和 A* pA = 新 A();

    在 C 中 以下两个动态对象创建之间的确切区别是什么 A pA new A A pA new A 我做了一些测试 但似乎在这两种情况下 都调用了默认构造函数 并且仅调用了它 我正在寻找性能方面的任何差异 Thanks If A是 POD 类
  • 使用安全函数在 C 中将字符串添加到字符串

    我想将文件名复制到字符串并附加 cpt 但我无法使用安全函数 strcat s 来做到这一点 错误 字符串不是空终止的 我确实设置了 0 如何使用安全函数修复此问题 size strlen locatie size nieuw char m
  • Windows 窗体不会在调试模式下显示

    我最近升级到 VS 2012 我有一组在 VS 2010 中编码的 UI 测试 我试图在 VS 2012 中启动它们 我有一个 Windows 窗体 在开始时显示使用 AssemblyInitialize 属性运行测试 我使用此表单允许用户
  • 如何在 Team Foundation 上强制发表有意义的签入评论?

    我有一个开发团队有一个坏习惯 他们写道poor签入评论 当我们必须在团队基础上查看文件的历史记录时 这使得它成为一场噩梦 我已经启用了变更集评论政策 这样他们甚至可以在签到时留下评论 否则他们不会 我们就团队的工作质量进行了一些讨论 他们很
  • 使用 LINQ 查找列表中特定类型的第一个元素

    使用 LINQ 和 C 在元素列表中查找特定类型的第一个项目的最短表示法是什么 var first yourCollection OfType
  • 我的 strlcpy 版本

    海湾合作委员会 4 4 4 c89 我的程序做了很多字符串处理 我不想使用 strncpy 因为它不会终止 我不能使用 strlcpy 因为它不可移植 只是几个问题 我怎样才能让我的函数正常运行 以确保它完全安全稳定 单元测试 这对于生产来
  • 网络参考共享类

    我用 Java 编写了一些 SOAP Web 服务 在 JBoss 5 1 上运行 其中两个共享一个类 AddressTO Web 服务在我的 ApplycationServer 上正确部署 一切都很顺利 直到我尝试在我的 C 客户端中使用
  • C 中的位移位

    如果与有符号整数对应的位模式右移 则 1 vacant bit will be filled by the sign bit 2 vacant bit will be filled by 0 3 The outcome is impleme
  • 检查 url 是否指向文件或页面

    我们需要以下内容 如果文件确实是文件 则从 URL 下载该文件 否则 如果它是一个页面 则什么也不做 举个简单的例子 我有以下命令来下载文件 My Computer Network DownloadFile http www wired c
  • 将应用程序从 Microsoft Access 迁移到 VB 或 C#.NET

    我目前正试图说服管理层需要将我们的应用程序之一移植到 NET 该应用程序已经发展成为 Access 中的一个庞然大物 SQL 后端 拥有 700 个链接表 650 个表单 子表单 130 个模块和 850 个查询 我几乎知道这样做的所有主要
  • 在 URL 中发送之前对特殊字符进行百分比编码

    我需要传递特殊字符 如 等 Facebook Twitter 和此类社交网站的 URL 为此 我将这些字符替换为 URL 转义码 return valToEncode Replace 21 Replace 23 Replace 24 Rep
  • 将日期参数传递给对 MVC 操作的 ajax 调用的安全方法

    我有一个 MVC 操作 它的参数之一是DateTime如果我通过 17 07 2012 它会抛出一个异常 指出参数为空但不能有空值 但如果我通过01 07 2012它被解析为Jan 07 2012 我将日期传递给 ajax 调用DD MM
  • 如何在内存中存储分子?

    我想将分子存储在内存中 这些可以是简单的分子 Methane CH4 C H bond length 108 7 pm H H angle 109 degrees But also more complex molecules like p
  • 更改显示的 DPI 缩放大小使 Qt 应用程序的字体大小渲染得更大

    我使用 Qt 创建了一些 GUI 应用程序 我的 GUI 应用程序包含按钮和单选按钮等控件 当我运行应用程序时 按钮内的按钮和字体看起来正常 当我将显示器的 DPI 缩放大小从 100 更改为 150 或 200 时 无论分辨率如何 控件的

随机推荐