2010-06-16 39 views
0
#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; 
} 

爲什麼如果我從這個字符串中刪除一個或多個字符,這段代碼會中斷?我認爲這與返回的迭代器有關,在高於終止迭代器的地址創建擦除操作後,但我不確定,它肯定是不正確的行爲。或者是?奇怪的迭代器行爲

+0

由於'begin()'在擦除字符時不會改變,所以將字符從'end()'擦除到'begin()'可能更容易。 – MSalters 2010-06-16 10:45:27

回答

8

這段代碼有幾個問題。

  1. 不要緩存值的s.end();它會在您刪除元素時發生變化。不要使用beg < end。慣用的方法是編寫beg != end。如果您嘗試迭代end,結果未定義,並且字符串庫的調試版本可能會故意導致進程崩潰,因此使用<是沒有意義的。
  2. 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; 
     } 
    } 
} 

編輯:我建議接受FredOverflow的答案。它比上面更簡單,更快捷。

+0

「不要緩存s.end()的值;它隨着刪除元素而變化。」 'auto'的一個主要問題。看看'auto end = s.end()'並告訴我這不會誤導語言新手! [一般評論;沒有特別提到這個OP] – 2011-06-21 22:30:28

+0

@Tomalak:我同意'auto'的非自明的含義是不幸的,但你是否暗示使用'auto'的選擇是不正確的? – 2011-06-22 03:12:41

+0

@Marcelo:一點都不! – 2011-06-22 08:38:29

4

存儲在end之前的s.end()值在s.erase()後無效。因此,不要使用它。

+0

我相信你是對的,但沒有多大意義,是嗎?爲什麼最終迭代器會失效? – 2010-06-16 10:16:45

+1

@A-ha:按定義無效。該標準如此說。 – 2010-06-16 10:18:31

+1

@ A-ha標準說的(正如馬塞洛正確指出的)有一個很好的理由。迭代器正在查看字符串的結束位置,並刪除了它的一個字符。它以前的值不再有效是合乎邏輯的。如果你想檢查新的結束,你必須再次詢問容器(s.end()),而不是使用先前緩存的值。 – 2010-06-16 10:20:57

1

請注意basic_string的語義和它的迭代器。

從www.ski.com/tech/stl

還要注意的是,根據C++標準,basic_string的具有非同尋常的迭代器失效語義。通過交換,保留,插入和擦除(以及相當於插入和/或擦除的函數,如清除,調整大小,追加和替換),迭代器可能會失效。另外,第一次調用任何非const成員函數,包括非const版本的begin()或operator [],都可能會使迭代器失效。 (這些迭代器失效規則的目的是讓執行者在實現技術有更大的自由。)

同樣會發生什麼,如果

beg = s.erase(beg); 

返回一個迭代相當於end()的

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

在調用擦除操作時,存儲的結束迭代器指針變爲無效。因此,在while循環條件下使用s.end()函數

0

您必須從.end() - 1迭代到.begin()。同時,使用==和!=以外的比較運算符是不安全的。

這裏是我的代碼:

vector<long long> myVector (my, my+myCount); 
    //sort and iterate through top correlation data counts 
    sort (myVector.begin(), myVector.end()); 
    cout << endl; 
    int TopCorrelationDataCount = 0; 
    bool myVectorIterator_lastItem = false; 
    vector<long long>::iterator myVectorIterator=myVector.end()-1; 
    while (true) {      
     long long storedData = *myVectorIterator; 
     cout << TopCorrelationDataCount << " " << storedData << endl;      

     //prepare for next item 
     TopCorrelationDataCount++; 
     //if (TopCorrelationDataCount >= this->TopCorrelationDataSize) break; 
     if (myVectorIterator_lastItem) break; 
     myVectorIterator--; 
     if (myVectorIterator==myVector.begin()) 
     { 
      myVectorIterator_lastItem = true; 
     } 
    } 

注意:它不能使用普通的做,因爲你如果要找出==()開始。如果是,這將是你最後一次迭代。你不能檢查==。begin() - 1,因爲它會導致運行時錯誤。

如果您只想使用矢量中的X個項目,請使用TopCorrelationDataCount。