为什么增强的 GCC 6 优化器会破坏实际的 C++ 代码?

2023-11-23

GCC 6 有一个新的优化器功能: 假设this始终不为空并基于此进行优化。

值范围传播现在假设 C++ 成员函数的 this 指针非空。这消除了常见的空指针检查但也破坏了一些不合格的代码库(例如 Qt-5、Chromium、KDevelop)。作为临时解决方法,可以使用 -fno-delete-null-pointer-checks 。可以使用 -fsanitize=undefined 来识别错误的代码。

变更文档明确指出这是危险的,因为它破坏了数量惊人的常用代码。

为什么这个新假设会破坏实际的 C++ 代码?粗心或不知情的程序员是否会依赖这种特定的未定义行为?我无法想象有人写作if (this == NULL)因为那太不自然了。


我想首先需要回答的问题是为什么善意的人们会写支票。

最常见的情况可能是您的类是自然发生的递归调用的一部分。

如果你有:

struct Node
{
    Node* left;
    Node* right;
};

在 C 语言中,你可以这样写:

void traverse_in_order(Node* n) {
    if(!n) return;
    traverse_in_order(n->left);
    process(n);
    traverse_in_order(n->right);
}

在 C++ 中,最好将其设为成员函数:

void Node::traverse_in_order() {
    // <--- What check should be put here?
    left->traverse_in_order();
    process();
    right->traverse_in_order();
}

在 C++ 的早期(标准化之前),人们强调成员函数是函数的语法糖,其中this参数是隐式的。代码是用 C++ 编写的,转换为等效的 C 语言并编译。甚至还有明确的例子来比较thisto null 是有意义的,最初的 Cfront 编译器也利用了这一点。因此,对于具有 C 语言背景的人来说,检查的明显选择是:

if(this == nullptr) return;      

注:Bjarne Stroustrup 甚至提到规则this这些年来已经发生了变化here

这在许多编译器上运行了很多年。当标准化发生后,情况发生了变化。最近,编译器开始利用调用成员函数,其中this being nullptr是未定义的行为,这意味着该条件始终是false,编译器可以随意省略它。

这意味着要遍历这棵树,您需要:

  • 致电前完成所有检查traverse_in_order

    void Node::traverse_in_order() {
        if(left) left->traverse_in_order();
        process();
        if(right) right->traverse_in_order();
    }
    

    这意味着还要检查每个调用站点是否可能有空根。

  • 不要使用成员函数

    这意味着您正在编写旧的 C 风格代码(可能作为静态方法),并使用对象作为参数显式调用它。例如。你又开始写作了Node::traverse_in_order(node);而不是node->traverse_in_order();在呼叫站点。

  • 我相信以符合标准的方式修复这个特定示例的最简单/最巧妙的方法是实际使用哨兵节点而不是nullptr.

    // static class, or global variable
    Node sentinel;
    
    void Node::traverse_in_order() {
        if(this == &sentinel) return;
        ...
    }
    

前两个选项似乎都不吸引人,虽然代码可以逃脱惩罚,但他们用this == nullptr而不是使用正确的修复方法。

我猜这就是其中一些代码库演变为具有this == nullptr检查他们。

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

为什么增强的 GCC 6 优化器会破坏实际的 C++ 代码? 的相关文章

随机推荐

  • Java |= 运算符问题[重复]

    这个问题在这里已经有答案了 我需要关于这个奇怪的操作员的帮助 你能向我解释一下这段代码的作用吗 Override public boolean addAll Collection
  • Jenkins Pull Request 构建器忽略带有 ${sha1} 的分支

    我正在尝试设置Jenkins PR 构建器插件在新的拉取请求上点击 github 我已经按照文档进行操作 并尝试了 许多 不同的配置 但我似乎无法克服这一点 忽略 refs heads jenkins testing 因为它与任何配置的 r
  • xargs:以并行模式将标准输出重定向到文件时丢失输出

    我在并行模式下使用 GNU xargs 版本 4 2 2 并且在重定向到文件时似乎确实会丢失输出 当重定向到管道时 它似乎工作正常 以下 shell 命令演示了最小 完整且可验证的示例的问题 我使用生成 2550 个数字xargs将其分成
  • 图像选择器 flutter web 1.9

    在新的 flutter web 1 9 上寻找图像选择器 我找到了一种方法 但小于 1 9 现在已合并 不知道如何实现此目的 尝试使用 dart html 但无法发布 仅在跑步时 看来对于Flutter web 1 10 dev Unive
  • 创建自定义方法安全表达式的最佳方法

    我正在尝试创建自己的方法安全表达式 我想在其中使用 PreFilter and PostFilter注释 在搜索教程和类似问题时 我发现了两种继续进行的方法 第一个是延长DefaultMethodSecurityExpressionHand
  • ./python:加载共享库时出错:libssl.so.1.1:无法打开共享对象文件:没有这样的文件或目录

    我需要在 Ubuntu 16 04 中尝试使用 openssl 1 1 1 的 python 3 7 python 和 openssl 版本都是预发布的 遵循有关如何统计地将 openssl 链接到 python 的说明以前的帖子 我下载了
  • JavaScript 中有哪些稀疏数组的用例?

    在稀疏数组比 常规 对象更好的情况下 您可以有什么可能的编程用途 我所说的稀疏数组是指 arr Initialize arr 0 W arr 1 T arr 3 F console log arr 0 undefined true cons
  • 嵌套期货未执行

    我遇到了一个奇怪的情况 我正在摆弄CompletableFuture当运行以下代码时 我得到了意想不到的结果 public static void main String args CompletableFuture
  • 计算链表中可能循环的节点数

    问题是这样的 它来自 Sedgwick 的优秀 Java 算法 q 3 54 给定一个指向不包含空链接的单链表中节点的链接 即每个节点要么链接到其自身 要么链接到列表中的另一个节点 确定不同节点的数量 而无需修改任何节点 并且使用不超过常量
  • 使用 Plack 处理多个文件上传

    尝试使用 Plack 处理多个文件上传 My form
  • subprocess.popen 和 subprocess.run 有什么区别

    我是新来的subprocess模块和文档让我想知道两者之间有什么区别subprocess popen and subprocess run 该命令的作用有区别吗 是不是只有比较新的一个 使用哪个更好 subprocess run 在Pyth
  • 在 macOS arm64 架构上使用 x86 库和 OpenMP

    我有一台 MacBook M1 并在我的机器上安装了一个针对 x86 Intel 架构编译的库 我有一些使用 OpenMP 的源代码 我想使用 clang 编译器编译我的代码并将我的可执行文件链接到 x86 库 我可以按照说明编译没有 x8
  • Tensorflow:如何创建 Pascal VOC 风格图像

    我正在致力于在 Tensorflow 中实现语义分割网络 并且我正在尝试弄清楚如何在训练期间写出标签的摘要图像 我想以类似的风格对图像进行编码类分割注释用于 Pascal VOC 数据集 例如 假设我有一个网络 其训练批次大小为 1 有 4
  • 如何查找3个或更多连续字符?

    我正在检查密码 这些功能之一是检查输入的密码是否连续重复 我还没有代码 因为我不知道该怎么做 我找到了这个正则表达式匹配两个或多个非连续的相同字符但它只匹配重复的逗号 以下是场景 5236aaa121 重复模式 因为a连续重复3次 2312
  • 在 PHP 中使用 uasort 访问数组键

    如果有一个相当基本的uasortPHP 中的函数如下所示 uasort arr function a b if a gt b return 1 if a lt b return 1 我尝试排序的数组如下所示 1642 gt 1 9314 g
  • 如何在简单适配器中的 imageview 中显示图像?

    我正在从 JSON 数组获取数据 并且可以在文本视图中显示文本 但在显示图像时遇到问题 这是主要活动 public class test extends ListActivity url to make request private st
  • 在 Azure 逻辑应用程序中反序列化 ServiceBus 内容

    我正在尝试读取 Azure 逻辑应用程序中消息的内容正文 但没有取得太大成功 我看到很多建议都说主体是base64编码的 并建议使用以下内容进行解码 json base64ToString triggerBody ContentData T
  • 使用snakeyaml将.yml文件加载到哈希图中(导入junit库)

    我正在尝试将 opencv 的 yml 文件加载到 arrayLists 均值 投影和标签中 我已经创建了这三个数组列表 并尝试将 yml 文件中的元素解析为它们 我发现了SnakeYAML 文档 但是我没有找到正确的方法 我正在尝试使用
  • 将 T[] 转换为 T[][] 的最快方法?

    So 事实证明并非所有数组都是一样的 多维数组可以具有非零下界 例如 请参阅 Excel PIA 的 Range Value 属性object rectData myRange Value 我需要将这些数据转换为锯齿状数组 我在下面的第一次
  • 为什么增强的 GCC 6 优化器会破坏实际的 C++ 代码?

    GCC 6 有一个新的优化器功能 假设this始终不为空并基于此进行优化 值范围传播现在假设 C 成员函数的 this 指针非空 这消除了常见的空指针检查但也破坏了一些不合格的代码库 例如 Qt 5 Chromium KDevelop 作为