2012-12-05 1 views
6

Was sind die meisten Bedrohungen für die Verwendung einer solchen Implementierung von Swap? Neben Fadensicherheit und schlechter Optimierung. Wann schlägt es fehl (Gegenbeispiel)?Sehr brutaler Austausch mit Vorlage, XOR und Zeiger auf den Speicher

template<typename T> 
void swapViaMemory(T& left, T& right) { 
    if(&left == &right) { return ; } 

    unsigned int tSize = sizeof(T); 
    unsigned char* lPtr = reinterpret_cast<unsigned char*>(&left); 
    unsigned char* rPtr = reinterpret_cast<unsigned char*>(&right); 

    for(unsigned int i = 0; i < tSize; ++i) { 
     *(lPtr + i) ^= *(rPtr + i); 
     *(rPtr + i) ^= *(lPtr + i); 
     *(lPtr + i) ^= *(rPtr + i); 
    } 
} 

Sorry für Grammatikfehler und falsche Schreibweisen (=

Antwort

4

Wenn T ein Element enthält, das zu einem anderen ihrer Mitte ein Zeiger oder eine Referenz ist dies fehlschlagen wird (die Absicht Annahme, daß für das Zeiger/Referenzelement immer Punkt/siehe das Datenelement, das zu dieser Instanz gehört).

struct foo 
{ 
    foo() : i(), ref_i(i), ptr_i(&i) {} 
    int i; 
    int& ref_i; 
    int *ptr_i; 
}; 

Wenn zwei Objekte foo, sagen f1 & f2 sind swapViaMemory vertauscht Verwendung nach Swapping, f1.ref_i und f1.ptr_i beziehen/Punkt f2.i und umgekehrt. Im Fall des Referenzelements ruft dies ein undefiniertes Verhalten auf, da es illegal ist, eine Referenz neu zu setzen.

+0

Dies gilt nicht für Zeiger-Member, es sei denn, Sie erweitern, was "dies wird fehlschlagen" bedeutet. –

+0

@LucDanton Zur Antwort hinzugefügt – Praetorian

+0

@Praetorian Ohh, das mag ich. Zeiger werden zwischen den Mitgliedern der vertauschten Objekte kreuzen. – shycha

4

Es scheitert in der Förder Vorsatz.

Welche der primäre Zweck des Codes ist.

template<typename T> 
    typename std::enable_if<std::is_pod<T>, void>::type 
    swapViaMemory(T& left, T& right) 
{ 
    using std::swap; 

    swap(left, right); 
} 
+3

Richtig, bis sich Ihre "Absicht" als ein Hund in der Praxis nicht langsam herausstellt, in diesem Fall geben Ihre Kunden nicht zwei Hufe über Ihre "Absicht". Ich sage nicht, dass das hier der Fall ist, aber im Allgemeinen besteht der Hauptzweck des Codes darin, die Sprache so zu kompilieren, dass wir * Probleme lösen können. Klarheit sollte immer angestrebt werden, aber sie sollte auch immer in den Hintergrund treten, um die Aufgabe gut und schnell zu erledigen. –

+3

@EdS. Dies ist hier nicht der Fall. Sogar "std :: copy" wird direkt in SSE-fähiges "memcpy"/"memmov" umgewandelt, wenn der Werttyp POD ist. Du musst ein Profil haben. Und dann stellt sich die Frage: "Kann ich diesen Hack *** hier *** benutzen", nicht "wann soll ich diesen Hack nicht *** benutzen" – sehe

+0

Einverstanden, weshalb ich meinen Kommentar qualifiziert habe. Ich war besorgt über die Aussage, dass "[Absicht] der Hauptzweck des Codes ist." *, Womit ich nicht einverstanden bin. Ich wollte auch schreiben "geht * langsam wie ein Hund" über. –

0

Neben schrecklich sein verschleiert, wenn die Besetzung links und rechts auf die gleiche Adresse zeigt

Da a^a = 0 (das ist, was Sie für diesen ‚Trick‘ verwenden)

Wenn left == right (und lässt annehmen, dass es ein 1-Byte-Einheit ist enthalten 'a' Dann tun Sie:

a^a = 0 
0^a = a 
a^a = 0 
+6

Wie? - Beachten Sie, dass es nichts für die Gleichheit tut. –

5

Es ruft nicht definiertes Verhalten, wenn T ist kein trivial kopierbarer Typ.

1

Say für:

struct B{ 
    virtual ~B() {} 
}; 
struct X : B 
{ 
    int x; 
    ~X() { std::cout << x; } 
}; 
struct Y : B 
{ 

}; 

//... 
X x = X(); 
Y y; 
swapViaMemory<B>(x,y); 
Verwandte Themen