2012-12-05 16 views
6

Quali sono le maggiori minacce nell'utilizzo di tale implementazione di swap? Oltre alla sicurezza del thread e alla scarsa ottimizzazione. Quando fallisce (controesempio)?Scambio molto brutale usando template, xor e puntatori alla memoria

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

dispiace per gli errori di grammatica e di ortografia (=

risposta

4

Se T contiene un membro che è un puntatore o riferimento ad un altro dei suoi membri fallirà (supponendo l'intento è per il membro puntatore/riferimento sempre punto/consultare il membro dati appartenente a quell'istanza).

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

Se due foo oggetti, dicono f1 & f2 vengono scambiati utilizzando swapViaMemory, dopo lo scambio, f1.ref_i e f1.ptr_i farà riferimento/scegliere f2.i e viceversa. Inoltre, nel caso del membro di riferimento, questo richiama un comportamento indefinito poiché è illegale riposizionare un riferimento.

+0

Questo non è vero per i membri del puntatore a meno che non si espanda cosa significa "questo fallirà". –

+0

@LucDanton Aggiunto alla risposta – Praetorian

+0

@Praetorian Ohh, mi piace. I puntatori incroceranno i punti tra i membri degli oggetti scambiati. – shycha

4

Fallisce nel trasporto di intenti.

Qual è lo scopo primario del codice.

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

Giusto, finché il tuo "intento" risulta non essere lento come un cane nella pratica, nel qual caso i tuoi clienti non danno due grida sul tuo "intento". Non dicendo questo è il caso, ma in generale, lo scopo principale del codice è compilare il linguaggio macchina in modo che * possiamo risolvere i problemi *. La chiarezza dovrebbe essere sempre perseguita, ma dovrebbe anche essere sempre in secondo piano per ottenere il lavoro fatto bene e rapidamente. –

+3

@ Eds. Questo non è assolutamente il caso qui. Anche 'std :: copy' ottimizzerà direttamente in' memcpy'/'memmov' abilitato SSE se il tipo di valore è POD. Devi profilo. E poi la domanda si trasforma in: "posso usare questo hack *** qui ***", non "quando dovrei *** non *** usare questo hack" – sehe

+0

concordato, motivo per cui ho qualificato il mio commento. Ero preoccupato dell'affermazione che * "[Intento] è lo scopo principale del codice." *, Di cui sono fortemente in disaccordo. Volevo anche scrivere sopra "risulta * essere * lento come un cane" sopra. –

0

Oltre ad essere terribilmente offuscato fallisce se il cast di sinistra e destra puntano allo stesso indirizzo

Dal a^a = 0 (che è quello che si usa per questo 'trucco')

Se left == right (e consente di assumere è un'entità 1 byte contenente 'a' allora si farà:

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

Come mai? - notare che non fa nulla per l'uguaglianza. –

5

Si invoca un comportamento indefinito se T non è un tipo banalmente copiabile.

1

Say Per:

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