2013-06-12 84 views
10

期間添加元素的矢量I已使用新的範圍爲基礎的由C++ 11標準提供的迴路和我想出了以下問題:假設我們迭代一個vector<>使用基於範圍的for,並且在迭代過程中我們在向量的末尾添加一些元素。因此,循環何時結束?基於範圍的環C++ 11

例如,查看此代碼:

#include <iostream> 
#include <vector> 
using namespace std; 
int main() { 
    vector<unsigned> test({1,2,3}); 
    for(auto &num : test) { 
     cout << num << " "; 
     if(num % 2) 
      test.push_back(num + 10); 
    } 
    cout << "\n"; 
    for(auto &num : test) 
     cout << num << " "; 
    return 0; 
} 

我 「-std = C++ 11」 標誌測試G ++ 4.8和蘋果LLVM版本4.2(鐺++),並且輸出是(對於兩種) :

1 2 3 
1 2 3 11 13 

注意,第一循環終止原向量的末尾,雖然我們添加其他元素,給它。似乎for-range循環僅在開始時評估容器結束。 這實際上是否是範圍正確的行爲?它是否由委員會規定?我們能相信這種行爲嗎?

注意,如果我們通過

for(vector<unsigned>::iterator it = test.begin(); it != test.end(); ++it) 

無效的迭代器改變第一循環,並拿出分段錯誤。

+0

儘管添加不是擦除,這是[在基於範圍的for循環內從容器中擦除元素]的副本(http://stackoverflow.com/questions/8624686/erasing-an-element- from-a-container-while-within-a-range-based-for-loop),因爲那裏的答案顯示了標準所說的範圍-for是 - 在循環開始之前確定並保存結束,並且保存的值在隨後的迭代中使用。 –

+1

@KateGregory我會認爲這不是重複的,因爲刪除當前元素對所有容器都是未定義的行爲,但添加元素只對'std :: vector','std :: deque','std: :unordered_set'和'std :: unorderd_map'。 –

+0

我看起來似乎是這個問題,由行爲略有不同。不管怎樣,謝謝。 –

回答

14

不,你不能依賴於這種行爲。修改循環內的向量會導致未定義的行爲,因爲循環使用的迭代器會在修改向量時失效。

範圍基於for循環

for (range_declaration : range_expression) loop_statement 

當修改矢量基本上等同於

{ 
    auto && __range = range_expression ; 
    for (auto __begin = std::begin(__range), 
     __end = std::end(__range); 
     __begin != __end; ++__begin) { 
      range_declaration = *__begin; 
      loop_statement 
    } 
} 

,迭代器__begin__end不再有效,並且提領__begin結果不確定的行爲。

+0

謝謝大衛。有趣的是,我的兩段代碼雖然基本上相同,但卻得出了非常不同的結果。 –

+2

其實,你缺少的disctinction 之間爲(自動_begin = r.begin(!); _begin = r.end(); ++開始) 和 爲(自動_begin = r.begin() ,_end = r.end(); _begin!= _end; ++ _ begin) (緩存r.end()) * *表示爲什麼你的程序會有工作的印象!迭代器指向矢量的舊版本。把一個析構函數放在包含的對象中,並且會出現鬧劇......:-D – Massa

+0

當向量被修改時,循環使用的_iterator無效_不一定。如果向量的容量足夠大而不需要重新分配,那麼所有迭代器保持有效。 –

0

可以,只要載體的容量足夠大,依賴於這種行爲,因此不需要重新分配。在調用push_back()之後,這將保證所有迭代器和引用除了過去末端迭代器之外的有效性。因爲end()在循環(見std::vector::push_back)開始時計算一次,這是好的。

你的情況,你必須增加test矢量的能力,以保證此行爲:基於對Is it legal to add elements to a preallocated vector in a range-based for loop over that vector?反應

vector<unsigned> test({1,2,3}); 
test.reserve(5); 

編輯,這是不確定的行爲的情況下。使用gcc,clang和cl構建的發行版本運行良好,但使用cl(Visual Studio)構建的調試版本將引發異常。

相關問題