2013-02-09 8 views
8

In Python, ich hatte man Werte von 2 Variablen zu tauschen, alles, was Sie tun müssen, warLauf Aussagen in ‚parallel‘

x,y=y,x 

man es, als ob die beiden statements- aussehen kann (x = y) und (y = x) werden parallel und nicht nacheinander ausgeführt.

Gibt es eine Möglichkeit, den gleichen Effekt in C++ zu erreichen?

NOTE/EDIT:

Ich suche diesen "parallel-Effekt zu erweitern, um kompliziertere Ausdrücke (falls vorhanden) wie
ones,twos= (ones^n)^~twos, (ones & n) | (twos & ~n);

Dies ist möglich, in Python, ist es möglich, in C++?

FAZIT:

So nach dem von leemes gegebene Antwort und die Kommentare auf seine Antwort:

1.You Boost-Bibliotheken in C++ 03 oder

verwenden können 2. Sie können C++ 11

verwenden, um auf die std::tie und std::tuple zuzugreifen, um diesen "parallelen" Effekt zu erreichen. Für die Gegenwart, markiere ich Leemes Antwort als akzeptiert, aber ich werde immer noch nach Methoden suchen, um diese coole Funktionalität in C++ 03 zu implementieren.

+3

'std :: swap (x, y);' ist der bevorzugte Weg. – chris

+3

@chris: Eigentlich ist 'std :: swap (x, y)' der falsche *** Weg. – Mehrdad

+1

@Mehrdad, guter Punkt. Mein Schwerpunkt lag auf der Verwendung der vorgefertigten Version, anstatt immer versuchen zu inline, aber das ist ein gültiges Problem. – chris

Antwort

18

Sonderfall: Swapping den Wert von zwei Variablen

(. Für die allgemeine Lösung, siehe unten)

zwei in C-Werte der Variablen vertauschen ++, sollten Sie immer swap verwenden:

using std::swap; 
swap(x, y);  // Do NOT say: std::swap(x, y) -- Read about Koenig lookup! 

stören sie nicht wie es es tun; es wird es tun sehr schnell. Die Implementierung der C++ - Standardbibliothek wird ihr Bestes tun, um dies zu einem Einzelbefehl zu optimieren, wenn der Prozessor dies unterstützt (aber der Standard teilt der Implementierung dies nicht mit). Für Register-Only-Variablen gibt es zum Beispiel die x86-Anweisung xchg, die es so schnell wie möglich macht. Versuchen Sie nicht, es mit einigen "drei XOR-Operationen" zu optimieren, es wird nicht schneller sein. Wenn Sie Pech haben, wird es nicht zu etwas wie xchg optimiert werden.

Die generische Operation swap in C++ 03 führt eine temporäre Variable ein und führt drei Kopienkonstruktionen aus. In C++ 11 gibt es move-semantics und die Objekte werden eher verschoben als kopiert.Für Ihre eigene Typen, lassen Sie uns einige Datenstruktur sagen, die nur einen Zeiger auf die tatsächlichen Daten enthält, sollten Sie dieses Verfahren optimieren, um es in konstanter Zeit zu machen ausführen:

  • In C++ 03, Sie können entweder std::swap spezialisieren oder Ihre eigene swap Funktion in Ihrem Namespace (see the two top answers on this question) implementieren, um das Swapping zu optimieren: Tauschen Sie einfach jedes Mitglied in Ihrer Klasse aus, um ihre Daten zu tauschen. Für das Datenstrukturbeispiel, das nur einen Zeiger enthält, vertauschen Sie einfach die Zeiger.

  • In C++ 11 gibt es die neue bewegt Semantik, die Sie Bewegung der Daten von einem auf ein anderes Objekt implementieren lassen, die in einem sehr ähnlichen Verhalten führen. (Verschiebungssemantik wurde für allgemeinere Probleme wie das Tauschen von zwei Objekten eingeführt: Wenn ein Objekt nicht mehr benötigt wird, aber ein anderes "Kopie" des ersten sein muss, kann es einfach verschoben werden.) Lesen Sie über Verschiebungssemantik und Konstruktor verschieben für Details.

  • Für sowohl C++ 03 und C++ 11 gibt es eine alternative Art und Weise: Sie können implementieren implizit gemeinsam genutzte Daten und copy-on-write für schwere Klassen wie Datenstrukturen. Im obigen Beispiel, in dem Ihre Datenstruktur einen Zeiger auf die tatsächlichen Daten enthält, implementieren Sie die Referenzzählung. Wenn Sie die Datenstruktur kopieren, erhöhen Sie einfach den Referenzzähler um eins. Stellen Sie beim Ändern der Daten sicher, dass es nicht freigegeben ist (ref count = 1), andernfalls "trennen" Sie es, indem Sie es nur dann kopieren. Dies führt zu einer konstanten Kopier- und Tauschoperation.


Allgemeiner Fall: Mehrere beliebige Ausdrücke

Für andere Aussagen, die nicht Eingabe/Ausgabe-abhängig sind, wie (a, b) = (x, y), sie nur schreiben „wie sie ist“, und es wird laufen zumindest perfekt pipelineed, da sie keine Abhängigkeit haben:

a = x; 
b = y; 

Wenn Sie sind Eingabe/Ausgabe abhängig, wie Ihr Beispiel in der Bearbeitung, können Sie es aufteilen und provisorisch einführen. Du wirst dir keinen Gefallen tun, wenn du versuchst, das mit einigen ausgefallenen Ausdruckstricks wie xor-ing zu lösen. Der Compiler kennt eine Menge Tricks für Assembler (wie xchg), man kennt nur Tricks, um solche in reinem C++ (wie xor) auszudrücken.

In C++ 11 gibt es std::tuple und std::tie, so dass Sie mehrere Ausdrücke ohne Einführung von Provisorien zuweisen können (sie werden hinter den Kulissen eingeführt, um die im Tupel gespeicherten Werte zu speichern und entweder vollständig oder bei dest nur Register mit ihnen, wenn möglich) zu halten:

using std::tie; 
using std::make_tuple; 
tie(ones, twos) = make_tuple((ones^n)^~twos, (ones & n) | (twos & ~n)); 

Beachten sie, dass die Typen von der rechten Seite Paar/Tupel haben die Zielwerte auf der linken Seite passen als Umwandlung hier nicht implizit ist.Wenn Probleme auftreten, führen Sie eine static_cast auf der rechten Seite, std::make_tuple die expliziten Typen erzählen oder einfach nur den Konstruktor für std::tuple erfordert explizite Typen verwenden, wie:

using std::tie; 
using std::tuple; 
tie(ones, twos) = tuple<int,int>((ones^n)^~twos, (ones & n) | (twos & ~n)); 
+0

Wer weiß, ob 'std :: tie 'vor C++ 11 existierte? Ich bin mir nicht sicher. Ich dachte es war, aber Google ist nicht gesprächig. Ist es nur im Boost verfügbar? – leemes

+1

Nein - C++ 03 hatte keine std :: tie oder Tupel (obwohl Boost sie in C++ 03 implementiert). –

+0

@JerryCoffin Danke für das Hinzeigen; Wie erwartet, gibt es nur eine nette Lösung für C++ 11, es sei denn, Sie möchten Boost in C++ 03 verwenden. – leemes

0

Wenn x und y Ebene ganze Zahlen sind, gibt es verschiedene schnelle Tricks sie in einer Zeile zu tauschen:

http://cpptruths.blogspot.com/2006/04/swapping-two-integers-in-one-liner.html

+1

Die meisten davon verursachen undefiniertes Verhalten, und selbst wenn dies nicht der Fall wäre, wäre es immer noch nicht schneller als das Beispiel mit drei Zeilen. –

+5

Tricks sind gut für Bildungszwecke, Code Quiz und Zeug, aber für echten Code verwenden Sie etwas wie 'std :: swap'. – leemes