2017-04-07 6 views
2

Ist das:Vorwärts Iterator/random acces Iterator und `Operator *` über temporäre Iteratoren

auto& ref1 = *it++; 
ref1 = expression; // (1) 

eine der erforderlichen Semantik eines Forward-Iterator? Und was ist mit einem Direktzugriffs-Iterator?

auto& ref1 = it[3]; 
ref1 = expression; // (2) 

Nach cppreference ein Vorwärts Iterator erforderlich ist, um:

// Return reference, which equals to (const) value_type & 
*it++ === value_type& 

und für einen Direktzugriffs Iterator:

it[n] === *(it + n) 

die die gleiche Situation ist, das heißt, in beide, dass Situationen, in denen Sie ein Temporäres dereferenzieren (der Iterator). In meinem Fall speichert mein Iterator einen Index, der es ermöglicht, auf einen Container zuzugreifen, der keinen direkten Zugriff auf die gespeicherten Elemente bietet, nur über den Index.

Das funktioniert gut:

*it++ = value; 

, da die temporäre Kopie von it hat Satz Umfang.

Aber in diesem Fall:

type& val = *it++; 
val = 3; 

wir nicht definiertes Verhalten zu bekommen, da die Kopie bereits in der zweiten Zeile zerstört wird.

In meiner Situation habe ich einen QModelIndex Wrapper, um Daten zu erhalten/speichern von/zu einem QAbstractItemModel. Das Modell gibt Ihnen nur Kopien der auf dem Modell gespeicherten QVariant s.

Meine Wrapper-Klasse (die value_type mit dem operator= überlastet) speichert eine Instanz eines QModelIndex (das Modell zu manipulieren), und der Iterator eine Instanz dieser Wrapper. Also, wenn der Iterator zerstört ist, auch der Wrapper und der Index.

Ich denke, dass ich beide Probleme lösen kann, solange die Linien (1) und nicht unterstützt werden müssen.

HINWEIS: Meine Implementierung ist wie, dass mehr oder weniger (vereinfacht):

// The value type 
struct index 
{ 
    QModelIndex qidx; 

    index& operator=(QVariant const& val) 
    { 
     if (qidx.isValid()) 
      qidx.model()->setData(qidx, val); 

     return *this; 
    } 
}; 

// Private class actually. The "movements" cannot be done 
// over the value type because it will cause, in functions 
// returning references to the value type, to increase the chaos. 
// So, I make the index points to different model items using 
// this class. 
struct index_manipulator 
{ 
    QModelIndex& qidx; 

    void move(int rows, int cols) 
    { 
     if (qidx.isValid()) 
      qidx = qidx.model()->index(qidx.row() + rows, 
             qidx.column() + cols); 
    } 
}; 

struct index_safe_ref 
{ 
    mutable index idx; 
    operator index&() const { return idx; } 
}; 

struct my_row_it 
{ 
    index idx; 
    index_manipulator manip = {idx.qidx}; 

    my_row_it(QAbstractItemModel* m, int col) 
     : idx(m ? m->index(0, col) : QModelIndex()) 
    {} 

    index& operator*() const { return idx; } 

    my_row_it operator++(int) const 
    { 
     auto copy = it; 
     manip.move(1, 0); 
     return copy; 
    } 

    index_safe_ref my_row_it::operator[](difference_type n) const 
    { 
     auto it = it + n; // Operator+ is over there. 
     return { it.idx }; 
    } 
}; 

Antwort

0

Dies wird durch eine allgemeine Aussage über Iteratoren bedeckt ist:

Zerstörung eines Iterators kann Zeiger ungültig und Referenzen, die zuvor von diesem Iterator erhalten wurden.

§24.2.1/9 N3337

Aber, wie T. C. weist in other answer darauf hin, dass Ihr Iterator kein gültiger Vorwärtsiterator (oder etwas, das strenger ist) sein kann, wenn Sie einen Verweis auf ein Objekt zurückgeben, das im Iteratorobjekt enthalten ist.

Ich sehe zwei Lösungen: Geben Sie das index Objekt nach Wert zurück, oder geben Sie einen Verweis auf einen Heap zugewiesen index Objekt zurück.


Als Hinweis, ein InputIterator diese unterstützen muss:

value_type temp = *iterator++; // or *iterator; ++iterator; 
// use temp 

Also in Ihrem Fall das funktionieren muss (sollte aber soweit ich sehen kann):

index temp = *iterator++; 
temp = expression. 
Diese

ist nicht dasselbe wie Zeile (1) weil obige Code eine Umwandlung in das value_type beinhaltet (und nicht ein Verweis darauf).

+0

My Iterator dies unterstützen. Zwei Kopien desselben Iterators beziehen sich auf denselben Gegenstand. Welche mein Iterator fullfill nicht ist & * it == & * (my_row_it (it)). –

1

A stashing Iterator (das heißt, ein Iterator, der einen Verweis auf etwas in mich selbst zurückgibt) ist nie ein gültiges vorwärts Iterator.

Iteratoren im Allgemeinen muss CopyConstructible ([iterator.iterators]/2.1 sein, die unter anderem verlangt, dass eine Kopie des Iterator auf das Original entspricht. Daraus folgt, dass ein Vorwärts Iterator und seine Kopie unbedingt gleich vergleichen müssen, und [forward.iterators]/6 erfordern, dass dass für zwei gleiche dereferenceable Iteratoren a und b, *a und *b müssen auf das gleiche Objekt gebunden werden, die nicht erfüllt für stashing Iteratoren sein kann.

Wenn Sie eine Anforderung zu ignorieren, schlage ich vor, die man ignorieren, das sagt reference muss ein tatsächlicher Referenztyp sein und Ihren Stashing-Iterator in einen Proxy-Iter verwandeln rator. Es ist für den in der Standardbibliothek der Praxis bewährt (vector<bool>::iterator) und jeder Bruch ist wahrscheinlich ein lauter Fehler bei der Kompilierung sein, anstatt still Laufzeit Unfug.

+0

Ich bin mein Fall, zwei Kopien des gleichen Iterators, bezieht sich auf das gleiche Element (das innere 'QAbstractItemModel' Element), weil zwei Kopien eines gleichen Iterators zwei Kopien eines' QModelIndex' haben, die sich auf dasselbe Element beziehen das 'Modell'. Wie ich in dem anderen Kommentar, in meinem Fall, '* it == * (my_row_it (it))', aber '& * it! = & * (My_row_it (it)) '. Also, was bedeutet "Äquivalent zum Original"? Zwei Kopien desselben Iterators geben nicht dasselbe Objekt zurück, sondern geben einen Proxy an dasselbe Objekt zurück. –

+0

Obwohl in der 'cppreference' -Dokumentation zumindest keine der geforderten Features über die Adresse des zurückgegebenen Objekts spricht, gibt es keine Möglichkeit zu wissen, ob zwei Objekte wirklich identisch sind, es sei denn, man vergleicht ihre 'addressof'. –

Verwandte Themen