2016-05-29 26 views
1

我剛這樣的代碼:分配(操作者=)無效迭代器容器

std::vector<int> v1 = { 1, 2, 3, 4 }; 
std::vector<int> v2 = { 7, 8, 9, 10 }; 
std::vector<int>::iterator it = std::next(v1.begin()); 
v1 = v2; 
int test = *it; 
std::cout << test; 

上面的代碼將引發錯誤:迭代不dereferencable。

但是,如果我用替換列表向量如下:

std::list<int> v1 = { 1, 2, 3, 4 }; 
std::list<int> v2 = { 7, 8, 9, 10 }; 
std::list<int>::iterator it = std::next(v1.begin()); 
v1 = v2; 
int test = *it; 
std::cout << test; 

的代碼只是跑預期沒有錯誤。
Iterator invalidation rulesstd::list::operator=,在調用operator =之後我被告知,除了結束迭代器之外,與此容器相關的所有迭代器,引用和指針都將失效。但爲什麼上面的代碼與std :: list的作品?我誤解了一些重要的東西嗎?

回答

4

當迭代器失效時,解引用它是未定義的行爲。因此,就規格而言,無論您如何看待這種行爲都無關緊要。根據您的期望,「工作」是允許的行爲之一。

FWIW(不多,TBH),我預計std::list賦值運算符來實現相當於是這樣的:

list& operator=(list const& rhs) { 
    if (this == &rhs) 
     return *this; 

    auto lhs_i = begin(); 
    auto rhs_i = rhs.begin(); 

    // write over the elements in any currently existing nodes, this 
    // avoids any unnecessary allocations 
    while (lhs_i != end() && rhs_i != rhs.end()) { 
     *lhs_i++ = *rhs_i++; 
    } 

    // erase any extra elements if size() > rhs.size() 
    erase(lhs_i, end()); 

    // push back additional elements if size() < rhs.size() 
    while (rhs_i != rhs.end()) { 
     push_back(*rhs_i++); 
    } 

    return *this; 
} 

而如果是,你可以看到,這樣的情況下,你的,列表都具有相同數量的元素,沒有元素被創建或銷燬,所以你會非常期待迭代器像平常一樣繼續工作。當然,這完全是推測,絕對不是你應該依賴的行爲,因爲即使你的實現是這樣,他們也可以在下一個版本中改變它,恕不另行通知。

+0

即使它似乎是「正常」它隨時可能一觸即發,沒有任何形式的通知。 –

1

這是未定義的行爲,但GCC有調試容器來捕捉這種行爲。

-D_GLIBCXX_DEBUG啓用:

 int test = *it; 
     ^~~~ 
/usr/local/include/c++/6.1.0/debug/safe_iterator.h:270: 

Error: attempt to dereference a singular iterator. 

Objects involved in the operation: 

    iterator "this" @ 0x0x7fff5f561e90 { 
     type = __gnu_debug::_Safe_iterator<std::__cxx1998::_List_iterator<int>, std::__debug::list<int, std::allocator<int> > > (mutable iterator); 
     state = singular; 
     references sequence with type 'std::__debug::list<int, std::allocator<int> >' @ 0x0x7fff5f561ef0 
    } 
bash: line 7: 16071 Aborted     (core dumped) ./a.out