热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

为什么不优化这个未使用的变量呢?-Whyisn'tthisunusedvariableoptimisedaway?

IplayedaroundwithGodboltsCompilerExplorer.Iwantedtoseehowgoodcertainoptimizationsare.

I played around with Godbolt's CompilerExplorer. I wanted to see how good certain optimizations are. My minimum working example is:

我试用了Godbolt的编译器浏览器。我想看看某些优化有多好。我的最小工作示例是:

#include 

int foo() {
    std::vector v {1, 2, 3, 4, 5};
    return v[4];
}

The generated assembler (by clang 5.0.0, -O2 -std=c++14):

生成的汇编程序(clang 5.0.0, -O2 -std=c++14):

foo(): # @foo()
  push rax
  mov edi, 20
  call operator new(unsigned long)
  mov rdi, rax
  call operator delete(void*)
  mov eax, 5
  pop rcx
  ret

As one can see, clang knows the answer, but does quite a lot of stuff before returning. It seems to my that even the vector is created, because of "operator new/delete".

正如大家所看到的,clang知道答案,但是回来之前做了很多事情。在我看来,由于“操作符new/delete”,甚至连向量都被创建了。

Can anyone explain to me what happens here and why it does not just return?

谁能向我解释一下这里发生了什么,为什么它不会回来?

The code generated by GCC (not copied here) seems to construct the vector explicitly. Does anyone know GCC is not capable to deduce the result?

GCC生成的代码(这里没有复制)似乎明确地构造了这个向量。有没有人知道GCC不能推断出结果?

3 个解决方案

#1


29  

std::vector is a fairly complicated class that involves dynamic allocation. While clang++ is sometimes able to elide heap allocations, it is a fairly tricky optimization and you should not rely on it. Example:

向量 是一个比较复杂的类,涉及动态分配。虽然clang++ +有时可以省略堆分配,但这是一个相当棘手的优化,您不应该依赖它。例子:

int foo() {
    int* p = new int{5};
    return *p;
}
foo():                                # @foo()
        mov     eax, 5
        ret

As an example, using std::array (which does not dynamically allocate) produces fully-inlined code:

例如,使用std::array (不动态分配)会生成完全内联的代码:

#include 

int foo() {
    std::array v{1, 2, 3, 4, 5};
    return v[4];
}
foo():                                # @foo()
        mov     eax, 5
        ret

As Marc Glisse noted in the other answer's comments, this is what the Standard says in [expr.new] #10:

正如Marc Glisse在另一个答案的评论中所指出的,这是该标准在[expr]中所说的。新)# 10:

An implementation is allowed to omit a call to a replaceable global allocation function ([new.delete.single], [new.delete.array]). When it does so, the storage is instead provided by the implementation or provided by extending the allocation of another new-expression. The implementation may extend the allocation of a new-expression e1 to provide storage for a new-expression e2 if the following would be true were the allocation not extended: [...]

实现可以忽略对可替换的全局分配函数的调用([new.delete.single], [new.delete.array])。当它这样做时,存储由实现提供,或者通过扩展另一个新表达式的分配来提供。如果分配没有扩展,则实现可以扩展新表达式e1的分配来为新表达式e2提供存储:[…]

#2


7  

As the comments note, operator new can be replaced. This can happen in any Translation Unit. Optimizing a program for the case it's not replaced therefore requires Whole-Program Analysis. And if it is replaced, you have to call it of course.

如注释所示,操作符new可以被替换。这在任何翻译单位都可能发生。因此,优化一个没有被替换的程序需要全程序分析。如果它被替换了,你当然要叫它。

Whether the default operator new is a library I/O call is unspecified. That matters, because library I/O calls are observable and therefore they can't be optimized out either.

默认操作符new是一个library I/O调用,但未指定。这很重要,因为库I/O调用是可观察的,因此它们也不能优化。

#3


4  

N3664's change to [expr.new], cited in one answer and one comment, permits new-expressions to not call a replaceable global allocation function. But vector allocates memory using std::allocator::allocate, which calls ::operator new directly, not via a new-expression. So that special permission doesn't apply, and generally compilers cannot elide such direct calls to ::operator new.

N3664改变[expr。在一个回答和一个评论中提到,允许新表达式不调用可替换的全局分配函数。但是vector使用std::分配器 :: allocation内存,它直接调用:::operator new,而不是通过一个新的表达式。因此,该特殊权限不适用,而且编译器通常无法避免对::operator new的这种直接调用。

All hope is not lost, however, for std::allocator::allocate's specification has this to say:

然而,对于std:::分配器 ::: distribution 's specification have this to say:

Remarks: the storage is obtained by calling ​::​operator new, but it is unspecified when or how often this function is called.

备注:存储是通过调用::::操作符new获得的,但是在调用该函数的时间或频率上是不指定的。

Leveraging this permission, libc++'s std::allocator uses special clang built-ins to indicate to the compiler that elision is permitted. With -stdlib=libc++, clang compiles your code down to

利用这个权限,libc+ 's std::分配器使用特殊的clang内置元素向编译器表明可以省略。使用-stdlib=libc++, clang将代码编译为

foo():                                # @foo()
        mov     eax, 5
        ret

推荐阅读
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
author-avatar
手机用户2502917387
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有