2016-05-29 20 views
1

ich einen Code wie folgt aus:Zuordnung (Operator =) entkräftet Iteratoren für Behälter

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; 

Der obige Code wird einen Fehler werfen: Iterator nicht dereferencable.

Wenn ich jedoch Vektor mit der Liste wie folgt ersetzen:

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; 

Der Code lief ebenso ohne Fehler zu erwarten.
Von , und die std::list::operator=, wurde mir gesagt, dass nach dem Aufruf von Operator =, alle Iteratoren, Referenzen und Zeiger in Bezug auf diesen Container ungültig sind, mit Ausnahme der Ende Iteratoren. Aber warum funktioniert der obige Code mit std :: list? Habe ich etwas Wesentliches falsch verstanden?

Antwort

4

Wenn ein Iterator ungültig gemacht wird, ist die Dereferenzierung eines nicht definierten Verhaltens. Daher ist jedes Verhalten, das Sie dabei beobachten, irrelevant, was die Spezifikation betrifft. "Arbeiten", gemäß Ihren Erwartungen, gehört zu den zulässigen Verhaltensweisen.

FWIW (nicht viel, TBH), erwarten würde ich der std::list Zuweisungsoperator zu so etwas äquivalent umgesetzt werden:

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

Und wenn es ist, kann man sehen, dass, für einen Fall wie Ihre, wo die Listen beide die gleiche Anzahl von Elementen haben, keine Elemente erzeugt oder zerstört werden, und so würden Sie sehr erwarten, dass Iteratoren genauso weiterarbeiten wie gewohnt. Dies ist natürlich nur Spekulation und definitiv kein Verhalten, auf das Sie sich verlassen sollten, denn selbst wenn dies für Ihre Implementierung der Fall ist, können sie es bei der nächsten Veröffentlichung ohne vorherige Ankündigung ändern.

+0

Und selbst wenn es „richtig funktioniert“ zu sein scheint es jederzeit ohne jede Art von Mitteilung brechen könnte. –

1

Es ist undefiniertes Verhalten, aber GCC hat Debug-Container, um diese Art von Verhalten zu erfassen.

Aktivieren Sie es mit -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