为什么局部静态对象的初始化使用隐藏的保护标志?

2023-11-22

C++ 中的局部静态对象在第一次需要时初始化一次(如果初始化有副作用,则这是相关的):

void once() {
    static bool b = [] {
        std::cout << "hello" << std::endl; return true;
    } ();
}

once第一次调用时会打印“hello”,但再次调用时不会打印“hello”。

我已经将这种模式的一些变体放入编译器资源管理器并注意到所有大牌实现(GCC、Clang、ICC、VS)本质上都做同样的事情:隐藏变量guard variable for once()::b创建,并检查主变量是否需要“这次”初始化;如果是的话,它会被初始化,然后设置保护,下次它不会跳到初始化代码。例如(通过调用替换 lambda 来最小化extern bool init_b();):

once():
        movzx   eax, BYTE PTR guard variable for once()::b[rip]
        test    al, al
        je      .L16
        ret
.L16:
        push    rbx
        mov     edi, OFFSET FLAT:guard variable for once()::b
        call    __cxa_guard_acquire
        test    eax, eax
        jne     .L17
        pop     rbx
        ret
.L17:
        call    init_b()
        pop     rbx
        mov     edi, OFFSET FLAT:guard variable for once()::b
        jmp     __cxa_guard_release
        mov     rbx, rax
        mov     edi, OFFSET FLAT:guard variable for once()::b
        call    __cxa_guard_abort
        mov     rdi, rbx
        call    _Unwind_Resume

...从 GCC 6.3 开始,带有 -O3。

这并不是没有道理的,而且我知道,在实践中,当条件一致时,条件跳转无论如何都接近于自由。然而,我的直觉仍然是通过un有条件跳转到初始化代码,作为其最后一个操作,将覆盖原始跳转nop指示。不一定是每个平台上的选项,但 x86 系列对于可以读取或写入的内容以及在何处似乎相当自由。

这个看似简单的想法有什么问题,以至于没有主流编译器使用它? (或者我只需要更加努力地尝试我的例子?)


这种“优化”在多线程环境中并不安全,即使在单线程环境中也可能不安全。

“nops”的写入可能需要多个指令。

在最终代码优化之前,jmp 指令的大小可能无法得知(是否需要 8、16 或 32 位偏移量?)

CPU 内的指令缓存不会检测到代码字节的变化,除非执行指令子集之一导致缓存被刷新。

所有这一切都假设代码可以通过数据段写入。

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

为什么局部静态对象的初始化使用隐藏的保护标志? 的相关文章

随机推荐

  • 升压 asio io_service.run()

    我只是想看一下 asio聊天服务器示例 我的问题是关于他们的使用情况io service run 功能 的文档io service run 函数说 run 函数会阻塞 直到所有工作都完成并且没有 更多处理程序被调度 或者直到 io serv
  • 使用 g++ 与 pragma 链接

    在 Visual C 中 可以通过以下方式链接到代码本身中的库 pragma comment lib libname lib g 中可能有类似的东西吗 The 升压配置库对自动链接有一些支持 使用特定编译器的相关编译器特定代码 然而 文档指
  • 如何在序列化 OData 响应时忽略 Null 值

    我需要从响应中完全省略空值字段 我可以通过修改正常 webapi 响应的 JsonFormatter 序列化设置来做到这一点 config Formatters JsonFormatter SerializationSettings Nul
  • 哪款相机会在移动设备中打开 getUserMedia API?前部还是后部?

    在桌面上使用getUserMedia API访问摄像头时 会打开网络摄像头 当然这对视频通信有帮助 但是在移动设备上使用时会调用哪个摄像头 前置摄像头还是后置摄像头 是否需要代码来选择相机 有一种解决方案 用户可以选择其中一台摄像机 使用
  • 从 PHP 检查 Google 地图点是否在多边形中

    我一直在寻找一种方法来检查一个点是否是多边形的一部分 该多边形是从文件加载的 与这个问题相关的所有答案都是用javascript解决的 但我需要在服务器端执行此操作 这是因为结果不需要作为 Web 客户端显示给用户 而是需要存储并稍后用作参
  • 我想使用 EBImage 包,但它说它不适用于我的 R 版本

    install packages 中的警告 软件包 EBImage 不可用 适用于 R 版本 3 2 4 修订版 现在该怎么办有什么帮助 请指导我 EBImage作为 Bioconductor 项目的一部分分发 要安装包 请使用 sourc
  • MongoDB 不区分大小写的键搜索

    我可以不区分大小写地查询值 但我想不敏感地查询键 以便用户可以以全部小写形式键入它们 这不起作用 因为它不是有效的 JSON lastName i Jones 除了将新的键集合作为值之外 是否有我可以使用的策略 目前还没有办法做到这一点 M
  • 无法在 Google App Engine 中调试 dev_appserver

    我不认为这个问题是 PyDev 所独有的 而是任何 python 调试器所独有的 使用 Eclipse 和 pydev 我无法在 dev appserver Google 应用程序引擎开发服务器 进程中中断 WSGI 处理程序 我不是 10
  • MySQL Workbench 会话看不到数据库更新

    我使用 deb 在 Ubuntu 系统中安装了 MySQL Workbench community 6 2 3 工作台会话似乎没有看到其他会话 应用程序 命令行客户端 对数据库完成的更新 DML 新会话能够在启动时看到数据库的正确状态 但随
  • 动态更改源后加载音频元素

    我的页面正文中出现了几个音频元素 他们看起来像这样
  • python中有内置的恒等函数吗?

    我想指出一个不执行任何操作的函数 def identity args return args 我的用例是这样的 try gettext find gettext gettext else identity 当然 我可以使用identity上
  • java.lang.ClassNotFoundException: org.joda.time.ReadablePartial

    我使用 Eclipse Luna 和 Jaspersoft Studio 插件 6 2 2 来生成 Web 应用程序的开发人员报告 从 Eclipse 插件运行一份基本的空白报告没有问题 但是当我从 java 类加载此 jrxml 时 我收
  • 如何使用 ajax POST 到 php

    我似乎不知道如何使用ajax 来发帖 我做了一个愚蠢的表格来尝试一下 即使将其一直削减到只有两个值 仍然无法让任何东西发挥作用 我的html是这样的
  • MS Graph API C# 将用户添加到组

    我一直在研究如何使用 Microsoft Graph API nuget 上提供的 dotnet C 库 从 Azure AD 组中添加 以及稍后删除 用户 Nuget MS Graph API 忽略与连接相关的所有其他内容GraphSer
  • 使用servicestack捕获异常

    我们使用 ServiceStack 来提供基于 REST 的服务已经有一段时间了 到目前为止 它的表现令人惊叹 我们所有的服务都写成 public class MyRestService RestService
  • 如何让任务计划程序从 powershell 脚本检测失败的错误代码

    我有一些 powershell 脚本 当它们内部出现故障时 我试图在 Windows 任务计划程序中将它们触发为失败状态 所以我在 powershell 脚本中做了类似的事情 我尝试了退出代码 1 或 99 但看起来 Windows 任务计
  • Python请求库如何使用单个令牌传递授权标头

    我有一个请求 URI 和一个令牌 如果我使用 curl s
  • 如何在C#中触发与最大化相关的事件

    考虑以下代码 Window myWindow new MyWindowSubclass myWindow BringIntoView myWindow Show Code which is effective as pressing the
  • 具有主键和唯一键的表意外锁定

    对于同时具有主键和单独的唯一索引的表上的事务 我遇到了 innodb 锁定问题 看起来如果 TX 使用唯一键删除一条记录 然后重新插入相同的记录 这将导致下一个键锁定而不是预期的记录锁定 因为键是唯一的 请参阅下面的测试用例以及我希望拥有哪
  • 为什么局部静态对象的初始化使用隐藏的保护标志?

    C 中的局部静态对象在第一次需要时初始化一次 如果初始化有副作用 则这是相关的 void once static bool b std cout lt lt hello lt lt std endl return true once第一次调