在循环中有常量函数返回值的优化吗?
Is there optimization for constant function return value inside a loop?
我的问题是关于gcc
编译器的。
通常,在循环中,我必须使用函数返回的值,该值在整个循环中都是常量。
我想知道是否最好事先将这个常量返回值存储在变量中(让我们想象一个长循环),或者像gcc
这样的编译器是否能够执行一些优化来缓存常量值,因为它会将其识别为常量抛出循环。
例如,当我循环遍历字符串中的字符时,我经常这样写:
bool find_something(string s, char something)
{
size_t sz = s.size();
for (size_t i = 0; i != sz; i++)
if (s[i] == something) return true;
return false;
}
但是如果有一个聪明的编译器,我可以使用下面的(更短更清楚):
bool find_something(string s, char something)
{
for (size_t i = 0; i != s.size(); i++)
if (s[i] == something) return true;
return false;
}
则编译器可以检测到循环内的代码没有对string
对象执行任何更改,然后将构建一个代码来缓存s.size()
返回的值,而不是为每次迭代进行(较慢的)函数调用。
gcc
有这样的优化吗?
一般来说,在您的示例中没有什么可以使编译器不可能在循环之前移动.size()
计算。事实上,GCC 5.2.0将为您展示的两个实现生成完全相同的代码。
然而,我强烈建议反对依赖这样的优化(在真正的性能关键代码中),因为某个地方的一个小变化(gcc的优化器,std::string
的实现细节,…)可能会破坏gcc进行这种优化的能力。
然而,我不认为在通常90%的代码中编写更冗长的版本有什么意义,因为这不是真正的性能关键。
对于当前的c++编译器,我会选择更简洁的:
bool find_something(std::string s, char something)
{
for (ch : s)
if (ch == something) return true;
return false;
}
与GCC 5.2.0的机器码非常相似。
编译器必须知道该对象没有在其他线程中被修改。它能判断出如果物体不变,函数也不会改变,但它不能判断物体在其他刺激下不会改变。
如果包含某种形式的整个程序优化,编译器将展开对具有size的成员的调用
这取决于编译器能否将函数调用识别为常量。考虑下面的函数,它可能驻留在编译器无法分析的外部库中。
int odd_size(string s) {
static int a = 0;
return a++;
}
无论输入参数如何,该函数都将返回不同的值。因此,即使传递的字符串对象保持不变,编译器也不能假定返回值为常量。
另一方面,如果编译器检测到常量函数调用,它可能会将常量表达式移出循环。
旧版本的gcc
有一个明确的选项-floop-optimize
来负责这个任务。来自gcc-3.4.5文档:
-floop-optimize
执行循环优化:将常量表达式移出循环,简化退出测试条件,并可选择进行强度降低和循环展开。
在-O, -O2, -O3, -O级别启用。
我在gcc
的当前版本中找不到这个选项,但我很确定它们也包括这种类型的优化
- 返回值优化:显式移动还是隐式
- 使用 std::p air 进行返回值优化
- C++ 特征图3.5,特征图不使用命名返回值优化?
- 我是否正确测试了返回值优化?
- 使用std::optional时的命名返回值优化
- 找不到使保证返回值优化工作的方法
- 局部堆栈变量成员的返回值优化
- 为什么 GCC 无法优化,除非返回值有名称?
- 优化的范围检查并返回值
- 在没有返回值优化的情况下将两个对象加在一起时,将创建多少个临时对象
- 为什么三元运算符阻止返回值优化
- 实现move构造函数如何影响返回值优化
- 内存分配,用于在C 11中循环中函数的返回值:如何优化
- 我如何确定将进行返回值优化
- 返回值优化并复制C中的ELINION
- 如何使编译器不优化 getter 的返回值并使其恒定
- 为什么我在此代码中没有得到返回值优化?
- 如果二进制运算符+重载的返回值是const,它会干扰优化吗
- 了解工厂方法和静态变量赋值的返回值优化 (Visual Studio)
- 返回值优化是否需要声明一个复制构造函数