赋值(operator =)使容器的迭代器无效

时间:2016-05-29 02:00:25

标签: c++ iterator containers invalidation

我有一个像这样的代码:

std::vector<int> v1 = { 1, 2, 3, 4 };  
std::vector<int> v2 = { 7, 8, 9, 10 };  
std::vector<int>::iterator it = std::next(v1.begin());  
v1 = v2;  
int test = *it;  
std::cout << test;   

上面的代码会抛出一个错误:迭代器不能解除引用。

但是,如果我用列表替换vector如下:

std::list<int> v1 = { 1, 2, 3, 4 };  
std::list<int> v2 = { 7, 8, 9, 10 };  
std::list<int>::iterator it = std::next(v1.begin());  
v1 = v2;  
int test = *it;  
std::cout << test;   

代码只是按预期运行而没有错误 从Iterator invalidation rulesstd::list::operator=开始,在调用operator =后,我被告知,除了最终迭代器之外,与此容器相关的所有迭代器,引用和指针都无效。但为什么上面的代码与std :: list有效?我误解了一些必要的东西吗?

2 个答案:

答案 0 :(得分:4)

当迭代器失效时,取消引用它是未定义的行为。因此,就规范而言,无论你采取何种行为都是无关紧要的。 &#34;根据您的期望,工作&#34;是允许的行为之一。

FWIW(不多,tbh),我希望std::list赋值运算符的实现等同于:

list& operator=(list const& rhs) {
    if (this == &rhs)
        return *this;

    auto lhs_i = begin();
    auto rhs_i = rhs.begin();

    // write over the elements in any currently existing nodes, this
    // avoids any unnecessary allocations
    while (lhs_i != end() && rhs_i != rhs.end()) {
        *lhs_i++ = *rhs_i++;
    }

    // erase any extra elements if size() > rhs.size()
    erase(lhs_i, end());

    // push back additional elements if size() < rhs.size()
    while (rhs_i != rhs.end()) {
        push_back(*rhs_i++);
    }

    return *this;
}

如果是,你可以看到,对于像你这样的情况,列表都有相同数量的元素,没有创建或销毁任何元素,所以你非常希望迭代器继续工作完全正常。当然,这完全是猜测,绝对不是你应该依赖的行为,因为即使是实施的情况,他们也可以在下一个版本中更改它而不另行通知。

答案 1 :(得分:1)

这是未定义的行为,但GCC有调试容器来捕获这种行为。

使用Attempt to reload List/Util.pm aborted. Compilation failed in require at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/Sub/Exporter/Progressive.pm line 9. BEGIN failed--compilation aborted at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/Sub/Exporter/Progressive.pm line 9. Compilation failed in require at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/Devel/GlobalDestruction.pm line 11. BEGIN failed--compilation aborted at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/Devel/GlobalDestruction.pm line 11. Compilation failed in require at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/Moo/_Utils.pm line 21. BEGIN failed--compilation aborted at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/Moo/_Utils.pm line 21. Compilation failed in require at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/Moo.pm line 4. BEGIN failed--compilation aborted at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/Moo.pm line 4. Compilation failed in require at /home/travis/build/xtaran/CGI-Github-Webhook/build_dir/lib/CGI/Github/Webhook.pm line 11. BEGIN failed--compilation aborted at /home/travis/build/xtaran/CGI-Github-Webhook/build_dir/lib/CGI/Github/Webhook.pm line 11. Compilation failed in require at ./cgitest.pl line 10. BEGIN failed--compilation aborted at ./cgitest.pl line 10. script /cgi-bin/cgitest.pl generated no valid headers at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/CGI/Test.pm line 468. Use of uninitialized value $in_fname in unlink at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/CGI/Test.pm line 469. Use of uninitialized value $in_fname in concatenation (.) or string at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/CGI/Test.pm line 469. can't unlink : No such file or directory at /home/travis/perl5/perlbrew/perls/5.22.0/lib/site_perl/5.22.0/CGI/Test.pm line 469.

启用它
-D_GLIBCXX_DEBUG