这个减量的顺序是否会调用未定义的行为?

Gal*_*lik 1 c++ containers stl erase undefined-behavior

我正在寻找确认,澄清这个代码是否定义良好.

通过将迭代器重新分配给容器erase()函数的结果来擦除循环中容器的元素是很常见的.循环通常有点像这样凌乱:

struct peer { int i; peer(int i): i(i) {} };

int main()
{
    std::list<peer> peers {0, 1, 2, 3, 4, 5, 6};

    for(auto p = peers.begin(); p != peers.end();) // remember not to increment
    {
        if(p->i > 1 && p->i < 4)
            p = peers.erase(p);
        else
            ++p; // remember to increment
    }

    for(auto&& peer: peers)
        std::cout << peer.i << ' ';
    std::cout << '\n';
}
Run Code Online (Sandbox Code Playgroud)

输出: 0 1 4 5 6

在我看来,假设它没有调用未定义的行为,以下可能会更整洁:

struct peer { int i; peer(int i): i(i) {} };

int main()
{
    std::list<peer> peers {0, 1, 2, 3, 4, 5, 6};

    for(auto p = peers.begin(); p != peers.end(); ++p)
        if(p->i > 1 && p->i < 4)
            --(p = peers.erase(p)); // idiomatic decrement ???

    for(auto&& peer: peers)
        std::cout << peer.i << ' ';
    std::cout << '\n';
}
Run Code Online (Sandbox Code Playgroud)

输出: 0 1 4 5 6

我认为这有效的原因如下:

  • peers.erase()将始终返回递增p,因此再次减少它是安全的

  • peers.erase(p)制作副本,p因为序列参考不会对错误的值进行操作

  • p = peers.erase(p)返回a,p&因此减量对正确的对象引用进行操作.

但我有些疑惑.我担心我正在调用错误的排序规则,使用--(p)相同的表达式,其中p用作参数,尽管它在纸上看起来没问题.

任何人都可以在这里看到我的评估问题吗?或者这个定义得很好?

Dan*_*rey 5

它取决于您用于检测要删除的元素的条件.如果你试图删除第一个元素将会失败,因为erase它将返回新元素,begin()然后你将它递减.这是非法的,即使您立即再次增加它.

为了避免这个错误,因为它更常见和可读,我坚持使用第一个版本.