C++ can';t使用迭代器遍历字符串:但是我的带有索引的版本确实有效

C++ can';t使用迭代器遍历字符串:但是我的带有索引的版本确实有效,c++,string,stl,iterator,C++,String,Stl,Iterator,我正在写一个小程序,将所有出现的正整数转换成二进制整数。那么我该怎么写呢 我有一个函数numbersToBinary,它接受一个字符串并对其进行修改,使其包含二进制形式的数字,而不是十进制形式的数字 void numbersToBinary(string &src) { for (string::iterator iter = src.begin(); iter != src.end(); iter++) { if (isdigit(*iter))

我正在写一个小程序,将所有出现的正整数转换成二进制整数。那么我该怎么写呢

我有一个函数numbersToBinary,它接受一个字符串并对其进行修改,使其包含二进制形式的数字,而不是十进制形式的数字

void numbersToBinary(string &src)
{
   for (string::iterator iter = src.begin(); iter != src.end(); iter++)
    {
        if (isdigit(*iter))
        {
           string::iterator numberStart = iter++; //numberStart = iter;
            while ((iter != src.end()) && (isdigit(*iter)))
            {
                iter++;
            }
            string ins = decimalToBinary(string(numberStart, iter));
            src.replace(numberStart, iter, ins);
        }
    }

}
问题在于,当使用以数字结尾的字符串调用replace方法时,该函数会捕获异常

下面是一个:代码,您也可以在这里看到:。单元测试可用

MWE:

但事实证明,条件(iter!=src.end())从来都不是假的,即使是在字符串末尾:

    Breakpoint 2, numbersToBinary (src="My favourite number is13and nevermind 13") at /home/pasha/projects/miem/Replacer/func.cpp:58
    58                  newString.append(ins);
    (gdb) print ins
    $40 = "1101"
    (gdb) s
    51          for (string::iterator iter = src.begin(); iter != src.end(); iter++) {
    (gdb) print iter
    $41 = 0 '\000'
    (gdb) s
    __gnu_cxx::__normal_iterator<char*, std::string>::operator++ (this=0x7fffffffd7d0) at /usr/include/c++/4.9.1/bits/stl_iterator.h:757
    757           { return __normal_iterator(_M_current++); }
    (gdb) s
    __gnu_cxx::__normal_iterator<char*, std::string>::__normal_iterator (this=0x7fffffffd780, __i=@0x7fffffffd788: 0x6a1a10 "") at /usr/include/c++/4.9.1/bits/stl_iterator.h:729
    729           : _M_current(__i) { }
    (gdb) s
    __gnu_cxx::operator!=<char*, std::string> (__lhs=16 '\020', __rhs=0 '\000') at /usr/include/c++/4.9.1/bits/stl_iterator.h:832
    832         { return __lhs.base() != __rhs.base(); }
    (gdb) s
    __gnu_cxx::__normal_iterator<char*, std::string>::base (this=0x7fffffffd7d0) at /usr/include/c++/4.9.1/bits/stl_iterator.h:794
    794           { return _M_current; }
    (gdb) s
    __gnu_cxx::__normal_iterator<char*, std::string>::base (this=0x7fffffffd810) at /usr/include/c++/4.9.1/bits/stl_iterator.h:794
    794           { return _M_current; }
    (gdb) s
    numbersToBinary (src="My favourite number is13and nevermind 13") at /home/pasha/projects/miem/Replacer/func.cpp:52
    52              if (isdigit(*iter)) {
    (gdb) print iter
    $42 = 16 '\020'
    (gdb) print src.end()
    $43 = 0 '\000'

在for循环结束之前,它可以工作!这是什么?

调用
replace
后,原始字符串值不再存在。因此,它的某些部分的迭代器不再有效。当您再次循环时,
iter
是一个迭代器,用于对不再存在的值的一部分进行迭代器,因此将其与另一个值的结尾进行比较是毫无意义的。调用
replace
后,需要将新字符串中的
iter
设置为正确的新值,然后再将其与
end
进行比较,以了解更新的(和…更新的)代码

编辑:难以置信,如果我加上这个

if (iter == src.end()) break;
if (iter == src.end()) break;
在for循环结束之前,它可以工作!这是什么

这并不令人难以置信。这就是for循环的工作原理。您需要了解何时执行for循环的增量步骤,以及何时计算条件步骤

在(重新)输入循环体之前,完成条件评估。在循环体完成后,在返回到循环顶部进行下一个条件求值之前,完成增量步骤

简而言之,如果内部数字循环运行到
src.end()。记住,for循环增量是在每次迭代完成之后,但在下一个条件测试之前完成的

所以,

void numbersToBinary(string &src)
{
    string newString;
    string::iterator iter = src.begin();
    while (iter != src.end())
    {
        if (isdigit(*iter))
        {
            string::iterator numberStart = iter++; //numberStart = iter;
            while ((iter != src.end()) && (isdigit(*iter))) {
                ++iter;
            }
            string ins = decimalToBinary(string(numberStart, iter));
            newString.append(ins);
        }
        else
        {
            newString.push_back(*iter++);
        }

    }
    src = newString;
}

是您尝试的几种方法之一。如果
iter
已经到达
src.end()
,您也可以在循环的末尾插入一个硬中断(尽管在那里检查似乎有些多余,因为我们已经知道它被设置为
src.end()
:数字循环)

调用
std::string::replace
可以使迭代器无效。您应该创建一个新的
结果
字符串并返回它。问题是字符串中可能有多个整数。我该怎么处理呢?在调用
replace
之后,我当然需要继续循环。您最好使用
[]
操作符(数组索引)…事情会变得不那么麻烦谢谢您,这很有意义。
if (iter == src.end()) break;
if (iter == src.end()) break;
void numbersToBinary(string &src)
{
    string newString;
    string::iterator iter = src.begin();
    while (iter != src.end())
    {
        if (isdigit(*iter))
        {
            string::iterator numberStart = iter++; //numberStart = iter;
            while ((iter != src.end()) && (isdigit(*iter))) {
                ++iter;
            }
            string ins = decimalToBinary(string(numberStart, iter));
            newString.append(ins);
        }
        else
        {
            newString.push_back(*iter++);
        }

    }
    src = newString;
}