Dan*_*ica 4 c++ optimization loops const vector
考虑以下代码:
int g(std::vector<int>&, size_t);
int f(std::vector<int>& v) {
int res = 0;
for (size_t i = 0; i < v.size(); i++)
res += g(v, i);
return res;
}
Run Code Online (Sandbox Code Playgroud)
编译器无法优化v.size()循环内的评估,因为它无法证明里面的大小不会改变g。用GCC 9.2 -O3和x64 生成的程序集是:
.L3:
mov rsi, rbx
mov rdi, rbp
add rbx, 1
call g(std::vector<int, std::allocator<int> >&, unsigned long)
add r12d, eax
mov rax, QWORD PTR [rbp+8] // load a poniter
sub rax, QWORD PTR [rbp+0] // subtract another pointetr
sar rax, 2 // result * sizeof(int) => size()
cmp rbx, rax
jb .L3
Run Code Online (Sandbox Code Playgroud)
如果我们知道这g不会改变v.size(),则可以如下重写循环:
for (size_t i = 0, e = v.size(); i < e; i++)
res += g(v);
Run Code Online (Sandbox Code Playgroud)
如果没有这些,和指令mov,这将生成更简单(因而更快)的汇编。的值只是保存在寄存器中。subsarsize()
我希望通过制作矢量可以达到相同的效果const(我知道它正在改变程序的语义,因为g现在不能更改矢量的元素,但这与问题无关):
int g(const std::vector<int>&, size_t);
int f(const std::vector<int>& v) {
int res = 0;
for (size_t i = 0; i < v.size(); i++)
res += g(v, i);
return res;
}
Run Code Online (Sandbox Code Playgroud)
现在,编译器应该知道在每次循环迭代中加载的那些指针不能更改,因此,
mov rax, QWORD PTR [rbp+8]
sub rax, QWORD PTR [rbp+0]
sar rax, 2
Run Code Online (Sandbox Code Playgroud)
总是一样的 尽管如此,这些指令还是存在于生成的程序集中。现场演示在这里。
我也尝试了Intel 19,Clang 9和MSVC 19,结果却完全相同。由于所有主流编译器的行为都如此统一,所以我想知道是否存在禁止这种优化的规则,即将size()恒定向量的求值移出循环。
加法const并不意味着g不能改变向量的大小。可悲的是。
如果您修改本身就是一个对象,则会得到UB const。const只要原始(即,被引用的)对象不是,则修改您具有引用的对象不是UB const。
换句话说,这是一个有效的程序:
int g(const std::vector<int>& v, size_t)
{
const_cast<std::vector<int>&>(v).clear();
return 0;
}
int f(const std::vector<int>& v) {
int res = 0;
for (size_t i = 0; i < v.size(); i++)
res += g(v, i);
return res;
}
void test()
{
std::vector<int> v;
f(v);
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果我们看不到的定义g,const即使我们不允许,也没有关系const_cast:
std::vector<int> global_v;
int g(const std::vector<int>& v, size_t)
{
global_v.clear();
return 0;
}
int f(const std::vector<int>& v) {
int res = 0;
for (size_t i = 0; i < v.size(); i++)
res += g(v, i);
return res;
}
void test()
{
f(global_v);
}
Run Code Online (Sandbox Code Playgroud)
考虑const将引用作为对您自己(和其他人)的提醒和编译器强制的保护措施,但不应该将其视为编译器的优化机会。但是,将值/对象const本身标记为改进优化的可能性很大-将实际值传递const Something给不透明的函数可以保证Something以后保留相同的内容(但请注意,这const不能通过指针或引用成员传递)。
| 归档时间: |
|
| 查看次数: |
84 次 |
| 最近记录: |