2012-02-16 79 views
2

我很困惑。我学到或被告知的是,如果调用擦除,则向量的迭代器将变为无效。但为什么下面的代码工作。它使用g ++编译并在Linux中运行。调用擦除后迭代器无效

#include <vector> 
#include <iostream> 

using namespace std; 

int main() { 
    vector<int> vec; 
    vec.push_back(1); 
    vec.push_back(2); 
    vec.push_back(3); 

    vector<int>::iterator it = vec.begin(); 
    ++it; 
    vector<int>::iterator it2; 

    it2 = vec.erase(it); 
    cout << "it: " << *it << endl; 
    cout << "it2: " << *it2 << endl; 
} 

感谢您的任何反馈!

+2

它“有效”,即它显示UB没有明显的症状。 – PlasmaHH 2012-02-16 11:13:41

+0

定义“代码工程”。做你所期望的是一个可能的结果_ [未定义的行为](http://stackoverflow.com/a/1553407/140719)_。 – sbi 2012-02-16 11:15:13

+0

当你使用gcc时,试着用'-D_GLIBCXX_DEBUG'运行,你就会开悟。希望。 – PlasmaHH 2012-02-16 11:18:48

回答

2

http://www.cplusplus.com/reference/stl/vector/erase/(未世界上最好的C++参考):

这会使所有迭代器和参考位置(或第一)和其随后的元件。

所以it无效;使用它会导致未定义的行为。事实上,你碰巧得到你所期望的是纯粹的运气不好。

+1

其实,我会叫它_bad_运气。当它立即崩溃时你很幸运,因为那时你意识到有什么事情是相反的。 ':)' – sbi 2012-02-16 11:16:37

+0

thx您的反馈。我想了想,但却无法相信它发生了。 – Orunner 2012-02-16 11:17:14

1

你在做什么是未定义行为,并认为它“作品”完全是偶然的。你不能也不可以永远依靠这个,因为它可以做任何事情。它的行为没有定义。

0

作为实施细节,vector<int>::iterator可以很容易地为int*。我认为在g++这是一个非常薄的包装围绕int*。如果是这样的话,那么擦除三元素向量的中间元素意味着it的指针数据成员被指向与被删除的元素相同的地址,这当然将包含先前在其之后的值,并且其也由it2有效地提及。

标准并不保证it仍然会引用任何内容,这就是为什么你不能依赖你在这里观察到的行为。但它解释了你所看到的。当你取消引用it时,一个实现几乎不得不使其他方式发生。但编译器每天都会走出困境:例如,调试库的版本,并且一些优化技术依赖于假设您的代码是正确的。