考虑以下代码:
using std::vector;
vector<vector<int>::iterator*> v;
vector<int> A{1,2,3,4};
vector<vector<int>::iterator> tmp(4);
int i=-1;
for (auto it=A.begin(); it!=A.end(); ++it) {
tmp[++i]=it, v.push_back(&tmp[i]);
}
for (auto& x: v)
std::cout<<**x<<" ";
当在MacOS 10.12.5上使用GCC 6.4.0编译时,会产生预期的输出1 2 3 4
。
但是,如果我们稍微修改上面的代码,就像这样:
using std::vector;
vector<vector<int>::iterator*> v;
vector<int> A{1,2,3,4};
vector<vector<int>::iterator> tmp;
for (auto it=A.begin(); it!=A.end(); ++it) {
tmp.push_back(it), v.push_back(&tmp.back());
}
for (auto& x: v)
std::cout<<**x<<" ";
抛出SIGSEGV
。为什么会这样?甚至第一个代码实现的行为依赖/未定义,我很幸运它有效吗?
答案 0 :(得分:3)
它抛出SIGSEGV。为什么会这样?
当v
需要重新分配内存以便能够存储下一个项目时,存储指向tmp.push_back(it)
中的对象的指针无效。
甚至第一个代码实现的行为依赖/未定义,我很幸运,它有效吗?
第一个代码块应该以可预测的方式工作,因为您创建了一个具有所需大小的向量,并且没有为该程序的其余部分更改其大小。如果你在向量上使用了push_back
,那么代码块也会受到未定义的行为的影响。
如评论中所述,您可以通过为向量中预期数量的元素保留空间来解决第二个代码块中的问题。
tmp.reserve(4);
for (auto it=A.begin(); it!=A.end(); ++it) {
tmp.push_back(it), v.push_back(&tmp.back());
}