2012-12-05 45 views
6

Các mối đe dọa nhất của việc sử dụng việc thực hiện hoán đổi này là gì? Bên cạnh luồng an toàn và tối ưu hóa kém. Khi nào nó thất bại (counterexample)?Hoán đổi rất tàn bạo bằng cách sử dụng mẫu, xor và con trỏ tới bộ nhớ

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

Xin lỗi cho những sai lầm ngữ pháp và lỗi chính tả (=

Trả lời

4

Nếu T chứa một thành viên mà là một con trỏ hoặc tham chiếu đến một của các thành viên này sẽ thất bại (giả sử mục đích là cho các thành viên con trỏ/tham chiếu đến luôn điểm/tham khảo thành viên dữ liệu thuộc về cá thể đó).

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

Nếu hai foo đối tượng, nói f1 & f2 được hoán đổi sử dụng swapViaMemory, sau khi trao đổi, f1.ref_if1.ptr_i sẽ giới thiệu/điểm đến f2.i và ngược lại. Ngoài ra, trong trường hợp thành viên tham chiếu, điều này gọi hành vi không xác định vì nó là bất hợp pháp để đặt lại một tham chiếu.

+0

Điều này không đúng đối với các thành viên của con trỏ trừ khi bạn mở rộng về ý nghĩa của 'điều này sẽ thất bại'. –

+0

@LucDanton Đã thêm vào câu trả lời – Praetorian

+0

@Praetorian Ohh, tôi thích điều đó. Con trỏ sẽ giao điểm giữa các thành viên của các đối tượng hoán đổi. – shycha

4

Nó thất bại trong vận chuyển về ý định.

Đó là mục đích chính của mã.

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

Phải, cho đến khi "ý định" của bạn hóa ra không chậm như một con chó trong thực tế, trong trường hợp khách hàng của bạn không đưa ra hai hoots về "ý định" của bạn. Không nói đó là trường hợp ở đây, nhưng nói chung, mục đích chính của mã là biên dịch sang ngôn ngữ máy để chúng ta * có thể giải quyết vấn đề *. Rõ ràng nên luôn luôn cố gắng, nhưng nó cũng luôn luôn phải mất một chỗ ngồi trở lại để có được công việc làm tốt và nhanh chóng. –

+3

@EdS. Đây hoàn toàn không phải là trường hợp ở đây. Ngay cả 'std :: copy' sẽ tối ưu hóa trực tiếp vào' memcpy'/'memmov' đã kích hoạt SSE nếu valuetype là POD. Bạn phải hồ sơ. Và sau đó câu hỏi được biến thành: "Tôi có thể sử dụng hack này *** ở đây ***", không "khi nào tôi không nên sử dụng hack này" – sehe

+0

Đồng ý, đó là lý do tại sao tôi đủ điều kiện nhận xét của tôi. Tôi đã quan tâm đến tuyên bố rằng * "[Ý định] là mục đích chính của mã." *, Mà tôi mạnh mẽ không đồng ý với. Tôi cũng có nghĩa là để gõ "hóa ra * được * chậm như một con chó" ở trên. –

0

Bên cạnh đó là khủng khiếp obfuscated nó thất bại nếu các diễn viên của trái và phải điểm đến cùng một địa chỉ

Kể từ a^a = 0 (đó là những gì bạn sử dụng cho điều này 'lừa')

Nếu left == right (và cho phép giả định đó là một thực thể 1 byte chứa 'a' Sau đó, bạn sẽ làm gì:

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

Làm thế nào? - chú ý nó không làm gì để bình đẳng. –

5

Nó gọi hành vi undefined nếu T không phải là một loại có thể sao chép được.

1

Say cho:

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