在C++中,可以使用以下代码计算vector<int>中所有元素的和:

vector<int> v = {1, 3, 7, 9};
sums = 0; for (int i = 0; i < v.size(); i++) {
sums += v[i];
}

  这是一段很普通的代码,问题在于:在这段代码中,v.size()会在循环开始前仅计算一次?还是会在每次循环中都计算一次?以前我总觉得,这段代码没有改变v的大小,既然我都能看出来,编译器一定也知道,从而会在循环开始前就把v.size()计算出来,之后的每次循环中,直接使用计算出的值,以减少函数调用的开销。但事实果真如此吗?

  使用g++编译上面这段代码,得到的结果如下:

  可以看到,每次循环时会调用v.size()获取vector大小。使用clang编译后的代码也大致类似,也会在每次循环调用v.size()获取大小:

  但这是否就意味着我想错了呢?并非如此。事实上,大家可能忽略了编译器有不同的优化等级,默认情况下,编译器会忠实地按照源代码的描述编译代码。当我们开启更高级别的优化时,就会得到“源代码来了也认不出”的编译结果:

  这里使用clang编译器编译并启用了-O2级别的优化。是的,你没有看错,启用此级别的优化后,循环直接被优化掉了。因为这里的vector<int>中只有4个固定的元素,因此编译器直接使用xmm(一种宽度为128位的加宽寄存器)替代了求和的循环。

  

  为了搞清楚启用优化后.size()是否会被提前计算出,我们创建一个更大的vector:

vector<int> v {};
for (int i = 0; i < 500; i++) {
v.push_back(i);
} int sums = 0;
for (std::size_t i = 0; i < v.size(); i++) {
sums += v[i];
}

  启用-O2级别的优化后,与求和循环相关的代码如下图所示:

  可以看到:v.size()会在循环开始前计算出,并保存到寄存器rdx中。在每次循环中,vector的索引(保存在r8中)直接与寄存器rdx中的值进行比较。

由于优化后使用的是128位的xmm寄存器,因此每次循环时r8会加上8.(一个xmm可以保存4个int,以上循环中每轮读取2次数据到xmm2中,因此共4x2=8个int数据)

  因此,在上述代码中,编译器是否会提前计算出.size()取决于启用优化的等级。

如果在循环中不改变vector的大小,C++编译器是否会将.size()优化为常数?的更多相关文章

  1. bash的循环中无法保存变量

    在bash中,如果循环在一个子shell中运行,那么在循环中对循环外面的变量的更改将在循环退出后不可见.像下面的例子: #!/bin/sh python run.py | while read lin ...

  2. Java循环中标签的作用(转)

    转自:http://lihengzkj.iteye.com/blog/1090034 以前不知道在循环中可以使用标签.最近遇到后,举得还是有其独特的用处的.我这么说的意思是说标签在循环中可以改变循环执 ...

  3. C#不允许在foreach循环中改变数组或集合中元素的值(注:成员的值不受影响)

    C#不允许在foreach循环中改变数组或集合中元素的值(注:成员的值不受影响),如以下代码将无法通过编译. foreach (int x in myArray) { x++; //错误代码,因为改变 ...

  4. ruby for in 循环中改变i的值无效

    ruby for in 循环中改变i的值无效 for j in 1..5 puts "#{j}hehe" j = j + 2 #break end 在循环中,使用j = j + 2 ...

  5. C++中数组和vector

    本文基于邓俊辉编著<数据结构(C++语言版)(第3版)>.<C++ Primer(第5版)>以及网上的相关博文而写,博主水平有限,若有不妥处,欢迎指出. 一.数组 C++中数组 ...

  6. 混编用到 C++中数组和vector 复习下大学课本

    本文基于邓俊辉编著<数据结构(C++语言版)(第3版)>.<C++ Primer(第5版)>以及网上的相关博文而写,博主水平有限,若有不妥处,欢迎指出. 一.数组 C++中数组 ...

  7. Java 循环中标签的作用

    continue和break可以改变循环的执行流程,但在多重循环中,这两条语句无法直接从内层循环跳转到外层循环.在C语言中,可以通过goto语句实现多重循环的跳转,但在非循环结构中使用goto语句会使 ...

  8. C#在foreach循环中修改字典等集合出错的处理

    C#在foreach循环中修改字典等集合出错:System.InvalidOperationException: Collection was modified; enumeration operat ...

  9. let 和 const 在for 循环中的使用

    在ES6 的规范中,多了两个声明变量的关键字: let 和const.初次学习的时候,只记住了 let 声明的变量只在for 的循环体中有效,循环结束后 变量就消失了, 同时const 也可以在for ...

  10. JS的splice()方法在for循环中使用可能会遇到的坑

    在写JS代码时,我们常常使用 splice 函数来删除数组中的元素,因为 splice 函数会直接对数组进行修改,从而不需再自己写一个算法来移动数组中的其他元素填补到被删除的位置.splice 功能十 ...

随机推荐

  1. vivo悟空活动中台 - 微组件多端探索

    本文首发于 vivo互联网技术 微信公众号 链接: https://mp.weixin.qq.com/s/oGX4XSm8F4fa1ocLdpyqlA作者:悟空中台研发团队 [悟空活动中台]系列往期精 ...

  2. Spring EL 表达式

    本篇讲述了Spring Expression Language -- 即Spring3中功能丰富强大的表达式语言,简称SpEL. SpEL是类似于OGNL和JSF EL的表达式语言,能够在运行时构建复 ...

  3. vue+elementUI+WebSocket接收后台实时消息推送

    vue+elementUI+WebSocket接收后台实时消息推送 https://blog.csdn.net/weixin_40888956/article/details/105971432?ut ...

  4. vant-list实现下拉加载更多

    1 <template> 2 <div class="home-wrapper"> 3 <div class="swipe-box" ...

  5. appium(二)安装(Android)

    一.安装Appium-desktop 1.官网下载安装包: http://appium.io/

  6. PMP项目变更管理及变更流程总结

    转载请注明出处: 1. 变更管理流程 2.变更管理流程十步: 0 预防--1发起变更请求--2分析影响--3备选方案--4CCB批准--5更新项目管理计划--6沟通干系人--7执行--8检查--9总结 ...

  7. The project description file (.project) for XXX is missing

    在STS中切换项目分支的时候,出现一个项目打不开了,提示:The project description file (.project) for XXX is missing 试了下网上的方法都没有解 ...

  8. Keep English Level-03

    rule -- 统治,管理,规章,制度 ruling -- 裁决 ruler -- 统治者,尺子 district judge -- 地方法官 sweeping -- 一刀切的 haul --拉 ov ...

  9. 函数指针、std::function、std::bind

    函数指针.std::function.std::bind 函数指针: C++语法中可以直接将函数名作为指针, void fun(int a, int b); 在这个函数声明中,函数指针即为fun,传入 ...

  10. Git-基本介绍