为什么string.insert(iterator,char)连续六次工作但不是七次? (C ++)

时间:2011-02-16 04:33:04

标签: c++ string insert iterator segmentation-fault

代码:

#include <iostream>
#include <string>

using namespace std;

string expand(string mask);

int main()
{
    string tiny = "blah blah [a-e] blah blah";
    string lengthy = "blah blah [a-i] blah blah";
    cout << expand(tiny) << endl;
    cout << expand(lengthy) << endl;
    return 0;
}


string expand(string mask)
{
    int i, range;

    /* find the first bracket, grab start letter */
    unsigned int bracket = mask.find("[");
    char start = mask[bracket + 1];

    /* point iterator at first bracket */
    string::iterator here = mask.begin();
    here += bracket;

    /* find second bracket, calculate ascii range */
    range = mask[bracket + 3] - mask[bracket + 1];

    /* kill brackets and their contents*/
    mask.erase(here, here + 5);

    /*** This loop causes an error on the 7th iteration ****/
    for(i = 0; i <= range; i++)
        mask.insert(here, (start + range) - i);

    return mask;
}

输出

  

matt @ Callandor:〜/ prog / tempVer $ g ++   test.cpp -o play

     

matt @ Callandor:〜/ prog / tempVer $ ./play

     blah blah abcde blah blah

     

blahblah defghi blah blah

     

*检测到glibc * ./play:free():下一个尺寸无效(快速):0x08353068

     

======= Backtrace:========= /lib/libc.so.6(+0x6c501)[0x5b5501] ...

我在尝试使用string :: insert(iterator,char)时遇到了一些奇怪的行为;我把它放在'for'循环中,我根本不移动迭代器,循环只是插入字符。如果我有六个或更少的字符要插入,它可以正常工作,但七个或更多的失败。

根据输出(见上文),看起来在六次插入之后,迭代器跳转到字符串的开头并开始插入垃圾。当程序结束时,我得到一个大的混乱错误。

在尝试隔离原因时,我尝试了两个循环(没有一个触及迭代器):

for(i = 0; i < 6; i++)
    mask.insert(here, (start + range) - i);
    cout << mask << endl;

for(i = 0; i < 7; i++)
    mask.insert(here, (start + range) - i);
    cout << mask << endl;

第一次完成就好了,第二次造成了分段错误。

有人知道这里发生了什么吗?

5 个答案:

答案 0 :(得分:9)

在倾注你的代码之后,我注意到你正在使用一个无效的迭代器。

简而言之,插入字符串会使其迭代器无效。插入后,here迭代器不再有效,因为在其他实现特定的细节中,字符串容量可能会增加。当插入后再次使用here迭代器时,这会导致未定义的行为,而不会先将其重置为修改后的字符串中的有效位。

答案 1 :(得分:2)

可能是因为当字符串必须调整大小时,内部字符串将位于内存中的不同位置,并且迭代器here将变为无效。

答案 2 :(得分:1)

std::basic_string<T>::insert使所有迭代器无效。因此here调用后insert无效。因此,程序具有未定义的行为,如果需要,可以格式化硬盘:)

说真的,你想要here = mask.insert(here, (start + range) - i);作为循环的主体。

哦,你应该确保find操作成功,然后继续:)

编辑:您可能最好将其重构为构建包含您要添加的内容的字符串,然后运行单个insert,而不是运行{{1} } insert,因为n会导致一个具有潜在二次时间的算法。

答案 3 :(得分:0)

我不太确定我是否有资格在这里给你建议,但它肯定闻起来就像你在数组的末尾索引。

答案 4 :(得分:0)

提问者问为什么它适用于6而不适用于7。

其他海报通过回答第二部分已经接近了,所以我将澄清插入可能使您的迭代器无效,但不一定。

如果insert必须重新分配内存,那么它将使迭代器无效。如果它不必重新分配内存,则迭代器可能不会失效。

因此你在前6次“幸运”但最终被抓住了。

你也正在删除5个元素,这样可能会使你的迭代器失效,但是在这种情况下你的迭代器可能只是作为一个指针或一个光包装器实现的,所以你再次“侥幸成功”。

你通常不应该依赖它,但是如果你先调用reserve()然后你只是做push_back()调用,你可以确定你的迭代器不会失效,直到你传递容量为止保留。