for*_*818 2 c++ windows dll optimization indexoutofboundsexception
我libstdc++-6.dll
在Windows中有问题.这段代码:
#include <iostream>
#include <vector>
int main(){
std::vector<int> x(10);
std::cout << x.at(3) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
编译好,但是当我运行它时,我收到一条错误消息说
程序入口点_ZSt24__throw_out_of_range_fmtPKcz无法位于DLL libstdc ++中 - 6.dll
我的问题不是如何解决这个问题(很可能是dll的错误版本,我只需要修复PATH).然而,这让我意识到一些非常意外的事情:
当我启用优化时,上面的代码运行良好(无论错误的dll如何),即
g++ error.cxx -O2
Run Code Online (Sandbox Code Playgroud)
但这段代码
#include <vector>
#include <iostream>
double Foo(const std::vector<int>& x,int index) {
int m = x.at(index + 1) - x.at(index);
int b = x.at(index);
return b/(m*1.0);
}
int main(){}
Run Code Online (Sandbox Code Playgroud)
才不是.
为什么我用第二个代码得到上面提到的错误,无论我是通过编译它
g++ error.cxx -O2 or g++ error.cxx
Run Code Online (Sandbox Code Playgroud)
?
同样,我知道为什么会出现错误,但我希望在启用优化的情况下,两个版本都不会导致错误.相反,第一个版本工作正常,而第二个版本没有.不应该-O2
完全消除边界检查?
Mar*_* Ba 10
C++标准要求边界检查,at()
实际的实现代码at()
确实包含边界检查.
但是在第一种情况下,边界是硬编码的(10个元素与索引3)并且"所有内容"都被内联-O2
,因此编译器的优化器会删除边界检查违规的代码,因为它可以在编译时证明不违反边界并且不采用代码路径(如果规则).
因此,在这种情况下,您不会收到链接器错误-O2
,因为编译器根本不会发出调用指令.
不应该-O2完全消除边界检查?
不,优化器必须遵守AS-IF规则,也就是说,如果优化器在编译时可以证明没有采用代码路径,那么它可以消除该代码.它不仅会毫不犹豫地删除源代码中引入的检查.
作为一个侧面说明,为vector::operator[]
的是不要求边界检查,实现可能(合理与否)介绍调试边界检查,当如NDEBUG
没有定义的,只有做任何检查时NDEBUG
被定义.但是,在这种情况下,如果您愿意,那么边界检查将被"预处理器"删除,而不是由优化器.