2016-11-14 29 views
0

我用poll()與std :: vector。 註冊收聽套接字。如何使用向量<T> :: reverse_iterator與一個元素

std::vector<struct pollfd> fds; 
fds.push_back(server_sock); 

並添加新的客戶端套接字或連接的客戶端會話做點什麼。

// poll() ... 
for(std::vector<struct pollfd>::reverse_iterator it = fds.rbegin(); it != fds.rend(); it++) { 
    if (it->fd == server_sock) { 
     struct pollfd newFd; 
     newFd.fd = newClient; 
     newFd.events = POLLIN; 
     fds.push_back(newFd); 
    } else { 
     // do something. 
    } 
} 

但是當存在1或2或4矢量元素時,reverse_iterator無法正常工作。我不明白爲什麼這項工作。

附帶示例代碼。

typedef struct tt_a { 
    int a; 
    short b; 
    short c; 
} t_a; 

vector<t_a> vec; 
for (int i = 0; i < 1; i++) { 
    t_a t; 
    t.a = i; 
    t.b = i; 
    t.c = i; 
    vec.push_back(t); 
} 

for(vector<t_a>::reverse_iterator it = vec.rbegin(); it != vec.rend(); it++) { 
    if (it->a == 0) { 
     t_a t; 
     t.a = 13; 
     t.b = 13; 
     t.c = 13; 
     vec.push_back(t); 
    } 

    printf("[&(*it):0x%08X][it->a:%d][&(*vec.rend()):0x%08X]\n", 
      &(*it), it->a, &(*vec.rend())); 
} 

printf("---------------------------------------------\n"); 

for(vector<t_a>::reverse_iterator it = vec.rbegin(); it != vec.rend(); ++it) { 
    if (it->a == 3) { 
     it->a = 33; 
     it->b = 33; 
     it->c = 33; 
    } 
    printf("[&(*it):0x%08X][it->a:%d][&(*vec.rend()):0x%08X]\n", 
      &(*it), it->a, &(*vec.rend())); 
} 

結果:

[&(*it):0x01ADC010][it->a:0][&(*vec.rend()):0x01ADC028] 
[&(*it):0x01ADC008][it->a:33][&(*vec.rend()):0x01ADC028] 
[&(*it):0x01ADC000][it->a:0][&(*vec.rend()):0x01ADC048] 

如果載體具有5個元素,它工作正常。

[&(*it):0x007620A0][it->a:4][&(*vec.rend()):0x00762078] 
[&(*it):0x00762098][it->a:3][&(*vec.rend()):0x00762078] 
[&(*it):0x00762090][it->a:2][&(*vec.rend()):0x00762078] 
[&(*it):0x00762088][it->a:1][&(*vec.rend()):0x00762078] 
[&(*it):0x00762080][it->a:0][&(*vec.rend()):0x00762078] 
--------------------------------------------- 
[&(*it):0x007620A8][it->a:13][&(*vec.rend()):0x00762078] 
[&(*it):0x007620A0][it->a:4][&(*vec.rend()):0x00762078] 
[&(*it):0x00762098][it->a:33][&(*vec.rend()):0x00762078] 
[&(*it):0x00762090][it->a:2][&(*vec.rend()):0x00762078] 
[&(*it):0x00762088][it->a:1][&(*vec.rend()):0x00762078] 
[&(*it):0x00762080][it->a:0][&(*vec.rend()):0x00762078] 
+0

Btw回答爲什麼這適用於1,2,4矢量大小的原因是由於矢量如何重新分配自己。我假設你的1,2,4矢量大小是你準備矢量的第一個循環。 矢量隨着size_needed + size_needed/2增長爲1,2,4,它需要通過使先前的分配無效並且您的矢量變爲無效來重新分配。 對於5的矢量容量應該是6(4 + 4/2)在那個時候有足夠的空間沒有移動分配的項目,所以它會工作。 – user3279954

回答

5

push_back invalidates iterators時,它會導致size超過容量:

如果新的大小()比容量大(),那麼所有的迭代器和引用(包括過去的最末端迭代器)是無效。否則只有最後一個迭代器失效。

基本上,如果您必須提前push_back,請確保提前reserve,以免您的迭代器失效。

+0

還有更多。反向迭代器比正向迭代器更容易失效,即使在獲得反向迭代器之前調用了vector :: reserve,上面的代碼仍會使迭代器無效。 –

+0

謝謝,ShadowRanger。我修復了我的代碼。在做push_back之後,我重新分配了迭代器值。 'vec.push_back(t); it = vec.rbegin()+ index + i; ' –

2

您的程序很有可能已經崩潰。您仍在迭代容器時操縱容器。

[&(*it):0x01ADC008][it->a:33][&(*vec.rend()):0x01ADC028] 

你可以看到垃圾'33',而它應該是'13'。

爲什麼你甚至試圖取消引用結束迭代

&(*vec.rend()) 

這基本上將是一個垃圾不論矢量大小的。它是一個未定義的行爲,會隨機地使應用程序崩潰。

由於陰影點出固定矢量大小迭代之前,但我仍然不知道如何將解決您的代碼作爲你的例子有,這將導致賽格故障

2

對於正常等問題(向前看,而不是反轉)向量迭代器,插入到向量中會使指向插入點或之後任何位置的任何迭代器無效。此外,如果矢量必須調整大小,則所有迭代器都將失效。

僅這一點就可以解釋你的問題,因爲,因爲你沒有(通過調用vec.reserve(SIZE))在您的載體預留的空間,任您push_back通話可能引發調整大小和無效的迭代器,這會導致不確定的行爲,當你嘗試之後使用它們。

但是,反向迭代器更加複雜,並且對於反向迭代器不具有相同的保證,並且我相信任何插入都可能導致它們失效。

在內部,反向迭代器在它指向的元素之後持有元素的向前迭代器。取消引用時,反向迭代器遞減此操作以轉發迭代器並返回其解除引用的值。所以rbegin()內部有end()的副本,而rend()有副本begin()。對於前向迭代器失效的上述規則意味着,至少,如果插入發生在反向迭代器的位置之後的任何點處,則反向迭代器將失效。所以如果你有一個迭代器指向長度爲1的向量中的索引0,則push_back將插入到索引1,這將使迭代器失效。如果您繼續使用該迭代器(例如在隨後的printf調用中解引用它時),那麼您將會有未定義的行爲。

未定義的行爲意味着任何事情都可能發生,而且通常不同的系統會產生不同的行爲。 不要認爲只是因爲此代碼按照預期在您的系統上運行,初始矢量大小爲5,它可以在其他系統上工作。任何調用未定義行爲的代碼本質上都是脆弱的,應該避免。

對我來說(運行Visual Studio 2015),無論矢量的大小如何,我都會在printf行發生崩潰。如果我打電話vec.reserve(10)來消除調整大小 - 無效問題,那麼它只會在vec初始長度爲1時崩潰。

此外,你在你的printf參數,這也是不確定的行爲提領vec.rend(),即使你只是想獲得一個地址出來。 (我不得不評論這個讓你的代碼運行,否則它會崩潰每次,即使沒有push_back電話。)

+0

在我的系統上(使用Visual Studio 2015,調試版本),我得到一個調試斷言失敗,給出錯誤「表達式:向量迭代器不可遞減」。我懷疑'&(* vec.rend())'相當於'&(*(vec.begin() - 1))',而vec.begin() - 1是非法的。 –

+0

不,「vec.begin() - 1」只有在您取消引用vec.rend()'時纔會發生。而'it!= vec.rend()'只會比較'it'的內部前向迭代器和'vec.rend()'的內部前向迭代器,而不需要減少內部前向迭代器。 –

+0

無論如何,這並不重要,因爲它是未定義的行爲,因爲不符合迭代器'operator *'的前提條件。與取消引用不存在的對象無關。我猜你使用了「解除引用」來表示「應用'*'運算符」,但'*'運算符首先是一個函數調用,並且只有滿足前提條件,我們才能討論函數的副作用,例如實際執行解引用。 –

相關問題