我在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时不进行检查。但是,在这种情况下,如果需要的话,边界检查将“由预处理器除去”,而不是由优化器除去。

10-06 04:13
查看更多