2016-09-02 20 views
10

Để khắc phục sự cố liên kết, tôi cần ghi nhớ tạm thời. Loại tạm thời nên là loại nào? gcc than phiền rằng reinterpret_cast sau sẽ phá vỡ các quy tắc bí danh nghiêm ngặt:Cách hành vi không xác định không xác định một đối tượng từ một mảng byte trong C++ 11 (hoặc sau này) là gì?

template <typename T> 
T deserialize(char *ptr) { 
    static_assert(std::is_trivially_copyable<T>::value, "must be trivially copyable"); 
    alignas(T) char raw[sizeof(T)]; 
    memcpy(raw, ptr, sizeof(T)); 
    return *reinterpret_cast<T *>(raw); 
} 

(ví dụ: khi T là "dài").

Tôi không muốn xác định T vì tôi không muốn tạo T trước khi ghi đè lên.

Trong liên minh, không viết một thành viên, sau đó đọc một số khác là hành vi không xác định?

T result; 
char * p = reinterpret_cast<char *>(&result); // or std::addressof(result) ! 

std::memcpy(p, ptr, sizeof(T));     // or std::copy!! 

return result; 

Không răng cưa vi phạm:

template<typename T> 
T deserialize(char *ptr) { 
    union { 
     char arr[sizeof(T)]; 
     T obj; 
    } u; 

    memcpy(u.arr, ptr, sizeof(T)); // Write to u.arr 
    return u.obj; // Read from u.obj, even though arr is the active member. 
} 
+7

Có một số [ngũ cốc] (https://uscilab.github.io/cereal/) và đừng lo lắng về điều đó. – nwp

+0

Tôi có [câu trả lời của luật sư ngôn ngữ về con trỏ và bí danh] (http://stackoverflow.com/a/12615861/726300), nhưng như báo trước đây là khu vực màu xám trong Tiêu chuẩn. Nó được cho là được cải thiện trong tương lai, nhưng tôi không có ý tưởng về hướng nào. Chương trình của bạn có thể được [tinh chỉnh] (http://coliru.stacked-crooked.com/a/1207492fe8779748) để theo dõi các quy tắc đối với lá thư, nhưng tôi không thể nói liệu các trình biên dịch có đồng ý hay không. Ít nhất GCC không phàn nàn nữa, nhưng điều đó có thể chỉ là do chúng tôi nhầm lẫn phân tích bí danh của nó. Đáng buồn là tôi không có thời gian để trả lời đúng. –

+0

@LucDanton: Tôi không nghĩ rằng ngay cả ['std :: launder'] (http://en.cppreference.com/w/cpp/utility/launder) cung cấp cơ sở mà OP mong muốn. –

Trả lời

6

gì bạn muốn điều này là. Nếu bạn muốn có số T, bạn cần có số T. Nếu loại của bạn là có thể sao chép một cách trivially, sau đó hy vọng nó cũng là trivially constructible và không có chi phí. Trong mọi trường hợp, bạn phải sao chép toán hạng trả về vào giá trị trả về hàm, và bản sao đó được ưu tiên, vì vậy thực sự không có thêm chi phí nào ở đây.

+1

Câu hỏi được hỏi một cách rõ ràng về việc thực hiện nó mà không cần xây dựng một 'T'. – nwp

+3

@nwp: Vâng, câu hỏi chỉ là sai về điều đó. –

+0

Có điểm nào trong việc truyền địa chỉ 'kết quả' sang' char * 'không? – user2079303

1

Bạn muốn sử dụng mẫu std::aligned_storage lớp học. Nó được thiết kế để xử lý vấn đề chính xác này. Đây là một giải pháp mẫu với một số SFINAE dựa trên kiểm tra của bạn trong câu hỏi của bạn.

template<class T> 
typename std::enable_if<std::is_trivially_copyable<T>::value, T>::type deserialize(const char *data) { 
    typename std::aligned_storage<sizeof(T), alignof(T)>::type destination; 
    std::memcpy(&destination, data, sizeof(T)); 
    return reinterpret_cast<T &>(destination); 
} 
+0

Đó vẫn là UB, phải không? Mục đích của 'aligned_storage' là một mục đích khác. –

+0

Nó không nên. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf – Andrew

+0

Tại sao một người trở lại tham chiếu đến không const tạm thời trong khi loại trả về không được tham chiếu? : 'reinterpret_cast (đích)' -> T – sandthorn

Các vấn đề liên quan