我在Windows中遇到libstdc++-6.dll
的问题。这段代码:
#include <iostream>
#include <vector>
int main(){
std::vector<int> x(10);
std::cout << x.at(3) << std::endl;
}
编译好,但是当我运行它时,我收到一条错误消息
程序入口点_ZSt24__throw_out_of_range_fmtPKcz无法在dll libstdc ++中找到 - 6.dll
我的问题是不如何解决这个问题(很可能是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
不应该完全消除边界检查吗?
答案 0 :(得分:10)
C ++标准要求at()
的边界检查,at()
的实际实现代码确实包含边界检查。
然而,在你的第一种情况下,边界是硬编码的(10个元素对比索引3)和&#34;所有东西&#34;内联-O2
,因此编译器的优化器会删除边界检查违规的代码,因为它可以在编译时证明边界没有被违反而代码路径没有采取(如果规则)。
因此,在这种情况下,你没有得到-O2
的链接器错误,因为编译器根本就没有发出调用指令。
不应该-O2完全消除边界检查吗?
不,优化器必须保持the AS-IF rule,也就是说,如果优化器在编译时可以证明没有采用代码路径,那么它可以消除该代码。它不会毫不犹豫地删除源代码中引入的检查。
作为旁注,对于不要求边界检查的vector::operator[]
,实现可以(合理地或不合理地)引入调试边界检查,例如, NDEBUG
未定义,仅在定义NDEBUG
时不进行检查。但是,在这种情况下,边界检查将被预处理器&#34;删除。如果你愿意,而不是优化者。
答案 1 :(得分:2)
C ++标准要求绑定检查std::vector::at
:
23.2.3序列容器
- 序列容器将所有相同类型的有限对象组织成严格的线性排列。该库提供了四种基本类型的序列容器:
醇>vector
,......
- 成员函数
at()
提供对容器元素的边界检查访问。如果at()
{/ 1}},out_of_range
会引发n >= a.size()
醇>
答案 2 :(得分:1)
std::vector::at
抛出异常。如果您不想要边界检查,请使用operator[]
。
m.at(index);
m[index]; //change to this
您的第一个示例不会抛出异常,因为std::vector<int> x(10);
会创建一个值为int
的{{1}}的向量,而不是一个值为0
的向量{ {1}}。
int