2016-05-10 8 views
8

Wenn Sie folgenden Code:Kann ich Vektor von Tupel von Referenzen sortieren?

std::vector<std::tuple<int&>> v; 
int a = 5; v.emplace_back(a); 
int b = 4; v.emplace_back(b); 
int c = 3; v.emplace_back(c); 
int d = 2; v.emplace_back(d); 
int e = 1; v.emplace_back(e); 
std::sort(std::begin(v), std::end(v)); 

mit gcc/libstdC++ kompiliert vs Klirren/libC++ binäre unterschiedliche Ergebnisse liefert.

Für gcc/libstdc++ wird ein Element auf alle anderen Referenzen kopiert.

5 4 3 2 1 
5 5 5 5 5 

Zuerst dachte ich, dass clang/libc++verhält sich wie erwartet, aber es funktioniert nur in einem Vektor zu 5 Elementen bis (denn es gibt einen Sonderfall für kleinen Behälter ist).

5 4 3 2 1 
1 2 3 4 5 

Bei der Weiterleitung mehrerer Elemente ähnelt das Ergebnis gcc.

5 4 3 2 1 0 
3 4 5 5 5 5 

So ist es gültig std::sort für Behälter von Tupeln mit Referenzen zu verwenden (das heißt mit std::tie gemacht, Teilmenge von struct Sortierung)? Wenn nicht, sollte ich irgendwelche Warnungen erwarten?

Antwort

6

So ist es gültig std::sort für Behälter von Tupeln mit Referenzen zu verwenden (das heißt mit std::tie gemacht, Teilmenge von struct Sortierung)? Wenn nicht, sollte ich irgendwelche Warnungen erwarten?

Nein, und nein. Einer der Typen Anforderungen an std::sort() ist, dass:

  • Die Art der dereferenzierte RandomIt muß die Anforderungen des MoveAssignable und MoveConstructible erfüllen.

wo MoveAssignable im Ausdruck erfordert t = rv:

Der Wert von t ist äquivalent den Wert von rv vor der Zuweisung.

Aber std::tuple<int&> ist nicht MoveAssignable weil int& nicht MoveAssignable ist. Wenn Sie einfach haben:

int& ra = a; 
int& rb = b; 

ra = std::move(rb); 

Der Wert von ra ist dem Stand der Wert von rb nicht gleichwertig. ra immer noch bezieht sich auf a, es ändert sich nicht auf b beziehen - was sich tatsächlich geändert hat, war der Wert von a.

Da unser Typ die Vorbedingung std::sort() nicht erfüllt, ist das Ergebnis des Aufrufs std::sort() nur undefiniertes Verhalten.


Anmerkung, die Sie konnte Art ein std::vector<std::tuple<std::reference_wrapper<int>>> aber, da std::reference_wrapper MoveAssignable liegt.

Beachten Sie auch, dass dies daran erinnert, nicht in der Lage zu sein, einen Container von auto_ptr nach einem alten Herb Sutter article zu sortieren.

+0

Die Verwendung von 'std :: reference_wrapper ' funktioniert, weil es aus 'std :: tie' konstruiert werden kann, aber einige Template-Magie benötigt, um T & ... type list zu bekommen und mit reference_wrapper zu dekorieren. zustimmen [Beiden Compiler] (http://melpon.org/wandbox/permlink/atQyUIr1Bh5g6qgn), dass 'std :: tuple ' is_move_assignable && is_move_constructible (mit den Standardmerkmalen) –

+0

@KarolWozniak Das Merkmal nur dann, wenn die tatsächlichen überprüfen semantische Werke - Sie * können * bewegen zuweisen ein 'Tupel '. Es hat einfach nicht das tatsächliche Verhalten, das diese Operation haben muss, um als MoveAssignable zu gelten. – Barry

+0

@KarolWozniak Zum Beispiel 'struct X {int val; X & operator = (X &&) {return * this; }; '' is_move_assignable 'ist wahr, aber' X' ist nicht wirklich MoveAssignable, da die Anforderung nicht erfüllt ist. – Barry

Verwandte Themen