2011-02-16 18 views
3

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

#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; 
} 

输出:

亚光@ Callandor:〜/ PROG/TEMPVER $克++ TEST.CPP -o玩

亚光@ Callandor:〜/ prog/tempVer $ ./play

blah blah abcde blah blah

等等等等defghi等等等等

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

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

我尝试使用string :: insert()时遇到一些奇怪的行为迭代器,炭);我把它放在'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; 

第一完成得很好,第二引起分段故障。

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

+0

你最后一个例子的缩进很容易让人误解。 – 2011-02-16 05:12:16

回答

9

经过您的代码,我注意到您正在使用无效的迭代器。

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

+0

太棒了!我想知道为什么string :: insert返回一个迭代器,现在它是有道理的。谢谢! – MatrixMan 2011-02-16 04:50:01

2

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

0

我不太确定我有资格在这里给你建议,但它确实闻起来像你索引过阵列末尾。

+0

我根本没有看到索引被使用;) – 2011-02-16 04:39:14

1

std::basic_string<T>::insert无效所有迭代器。因此hereinsert调用后无效。因此,该程序具有未定义的行为,并允许格式化您的硬盘,如果它想要的话:)

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

哦,你应该确保find运行程序:)

编辑之前成功:你可能会更好过重构这个弄成它建立包含要添加什么样的字符串,然后运行单个insert,而不是运行n插入,因为n会将结果插入具有潜在二次时间的算法中。

+0

当然!你是最棒的,谢谢。 – MatrixMan 2011-02-16 04:52:35

0

提问者问为什么它工作了6而不是7

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

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

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

你也在擦除5个元素,这样可能会使你的迭代器失效,但是在这种情况下,你的迭代器可能只是作为一个指针或者一个轻量级包装器来实现,所以你再也不用去了。

你通常不应该放弃它,但在你第一次调用reserve()然后你只是执行push_back()调用的情况下,你可以肯定你的迭代器不会失效,直到你通过容量你保留了。

相关问题