我今天正在玩一些代码,并且发现以下代码在Visual C ++中崩溃时非常惊讶。它看起来不错吗?当我运行代码时,gcc打印出1。英特尔也是如此。
#include <iostream>
#include <set>
#include <assert.h>
int main()
{
std::set<int> sampleSet;
sampleSet.insert(1);
sampleSet.insert(2);
sampleSet.insert(3);
std::set<int>::iterator normalIt(sampleSet.begin());
std::set<int>::reverse_iterator reverseIt(sampleSet.rbegin());
++normalIt;
++reverseIt;
int test1(*reverseIt); // 2
assert(*normalIt == *reverseIt); //they're both = 2
std::set<int>::iterator gonnaDelete((++reverseIt).base()); // gonnaDelete points to 2
int test2(*reverseIt); // 1
sampleSet.erase(gonnaDelete);
int test3(*reverseIt); // 1??? Visual Studio 2010 crashes here.... gcc is fine, but not sure if this is legal
std::cout << test3 << std::endl;
return 0;
}
答案 0 :(得分:1)
std :: vector :: erase(i)在“i”
之前引用任何引用vector元素的迭代器无效答案 1 :(得分:1)
这不合法。根据C ++ 98中的[lib.associative.reqmts],“擦除成员只能使迭代器和对擦除元素的引用无效。”因为reverse_iterator的定义类似于:
template<typename Iter>
class reverse_iterator {
Iter current;
Iter tmp;
public:
...
Iter base() { return current; }
reference operator*() {
tmp = current;
--tmp;
return *tmp;
}
};
当您删除gonnaDelete
时,您也会使reverseIt.current
无效,因此当您随后取消引用reverseIt
时,您将获得未定义的行为。
现在,set迭代器往往是指向节点的简单指针,而优化的分配器有时会单独留下已删除节点的内存,因此即使在使其中一个失效之后,代码有时也会按照您的意愿执行,但它是根本没有保证工作。我怀疑VC ++默认启用调试模式来捕捉这种错误。要启用gcc的等效模式,请尝试使用-D_GLIBCXX_DEBUG
构建:http://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/manual/manual/bk01pt03ch17s03.html