2011-02-16 19 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()調用的情況下,你可以肯定你的迭代器不會失效,直到你通過容量你保留了。

相關問題