[英]Can C++ compilers optimize calls to at()?
由于通过 [] 运算符进行的常规数组访问是未经检查的,因此当您的程序存在远程代码执行漏洞或由于缓冲区溢出导致数据泄漏时,登上头条并不有趣。
大多数标准数组容器都包含at()
方法,该方法允许对数组元素进行边界检查访问。 这使得越界数组访问定义良好(抛出异常),而不是未定义的行为。
这基本上消除了缓冲区溢出任意代码执行漏洞,并且还有一个clang-tidy 检查,警告您应该在索引非常量时使用at()
。 所以我改了好几个地方。
大多数托管语言都检查了 arrays ,并且它们的编译器可以尽可能消除检查。
我知道 C++ 编译器可以做很棒的优化。 问题是 C++ 编译器可以这样做以消除对at()
的调用,当他们看到它不能溢出时?
这是一个在托管语言中将受到边界检查消除的经典案例:迭代到大小。
#include <vector>
int test(std::vector<int> &v)
{
int sum = 0;
for (size_t i = 0; i < v.size(); i++)
sum += v.at(i);
return sum;
}
这不像索引和大小都是常量(可以通过常量传播解决)那样进行优化,它需要对值之间的关系进行更高级的推理。
正如 Godbolt 所见,GCC (9.2)、Clang (9.0.0) 甚至 MSVC (v19.22) 都可以合理地处理此类代码。 GCC 和 Clang 自动矢量化。 MSVC 只生成一个基本循环:
$LL4@test:
add eax, DWORD PTR [r9+rdx*4]
inc rdx
cmp rdx, r8
jb SHORT $LL4@test
这还不错,但考虑到它确实矢量化了一个使用[]
而不是.at()
的类似循环,我不得不得出结论:是的,即使在我们可能的某些基本情况下使用at
也会产生巨大的成本否则(特别是考虑到没有范围检查,所以自动矢量化步骤似乎没有理由害怕)。 如果您选择仅针对 GCC 和 Clang 则问题较少。 在更棘手的情况下,GCC 和 Clang 也可能“非常混乱”,例如在通过数据结构传递索引时(不太可能的代码,但重点是,范围信息有时会丢失)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.