我在Windows中的libstdc++-6.dll
有问题。这段代码:
#include <iostream>
#include <vector>
int main(){
std::vector<int> x(10);
std::cout << x.at(3) << std::endl;
}
编译正常,但是当我运行它时,我收到一条错误消息,说
我的问题是而不是如何解决此问题(很可能是dll版本错误,我只需要修复PATH)。但是,这使我意识到一些出乎意料的事情:
当我打开优化功能时,以上代码运行良好(无论错误的dll如何),即
g++ error.cxx -O2
但是这段代码
#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(){}
才不是。
无论我是否通过第二个代码进行编译,为什么都出现上述错误?
g++ error.cxx -O2 or g++ error.cxx
?
同样,我知道为什么会出现该错误,但是我希望打开优化后,两个版本都不会导致该错误。相反,第一个版本可以正常工作,而第二个版本则不能。
-O2
不应该完全消除边界检查吗? 最佳答案
C++标准要求对at()
进行边界检查,而at()
的实际实现代码确实包含边界检查。
但是,在第一种情况下,边界是硬编码的(10个元素,而索引3),并且“一切”都用-O2
内联,因此编译器的优化器会删除违反边界检查的代码,因为它可以在编译时证明确保不违反边界且未采用代码路径(按规则)。
因此,在这种情况下,您不会收到-O2
的链接器错误,因为编译器根本没有发出调用指令。
不,优化器必须保留the AS-IF rule,即,如果优化器可以在编译时证明未采用代码路径,则可以消除该代码。它不仅会故意删除源代码中引入的检查。
附带说明一下,对于不需要边界检查的vector::operator[]
,实现可以(例如合理地)引入调试边界检查,例如未定义NDEBUG
,仅在定义NDEBUG
时不进行检查。但是,在这种情况下,如果需要的话,边界检查将“由预处理器除去”,而不是由优化器除去。