奇怪的迭代器行为

The*_* do 0 c++ iterator

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
    string s = "Haven't got an idea why.";
    auto beg =  s.begin();
    auto end = s.end();
    while (beg < end)
    {
        cout << *beg << '\n';
        if (*beg == 'a')
        {//whithout if construct it works perfectly
            beg = s.erase(beg);
        }
        ++beg;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么如果我从此字符串中删除一个或多个字符,此代码会中断?我认为它与返回迭代器有关,因为擦除操作是在比end迭代器更高的地址创建的,但是我不确定它肯定是不正确的行为.或者是吗?

Mar*_*tos 8

这段代码有几个问题.

  1. 不要缓存值s.end(); 它会在您删除元素时更改.
  2. 不要用beg < end.惯用的方法是写beg != end.如果您尝试迭代过去end,结果是未定义的,并且字符串库的调试版本可能会故意使您的进程崩溃,因此使用它是没有意义的<.
  3. 从中返回的迭代器s.erase(beg)可能是s.end(),在这种情况下++beg将带您越过末尾.

这是(我认为)正确的版本:

int _tmain(int argc, _TCHAR* argv[])
{
    string s = "Haven't got an idea why.";
    for (auto beg = s.begin(); beg != s.end();)
    {
        cout << *beg << '\n';
        if (*beg == 'a')
        {//whithout if construct it works perfectly
            beg = s.erase(beg);
        }
        else
        {
            ++beg;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:我建议接受FredOverflow的回答.它比上面更简单,更快捷.


fre*_*low 6

从矢量或字符串逐个擦除元素具有二次复杂性.有更好的线性复杂解决方案:

#include <string>
#include <algorithm>

int main()
{
    std::string s = "Haven't got an idea why.";
    s.erase(std::remove(s.begin(), s.end(), 'a'), s.end());
    std::cout << s << std::endl;
}
Run Code Online (Sandbox Code Playgroud)