2016-09-02 2 views
10

संरेखण के मुद्दों को दूर करने के लिए, मुझे अस्थायी में memcpy की आवश्यकता है। उस प्रकार का अस्थायी होना चाहिए? जीसीसी शिकायत है कि निम्नलिखित reinterpret_cast सख्त अलियासिंग नियमों को तोड़ने जाएगा:सी ++ 11 (या बाद में) में बाइट सरणी से ऑब्जेक्ट को deserializing का कोई अपरिभाषित व्यवहार तरीका क्या है?

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

(जैसे जब टी "लंबे समय" है)।

मैं टी को परिभाषित नहीं करना चाहता, क्योंकि मैं इसे ओवरराइट करने से पहले टी बनाना नहीं चाहता हूं।

एक संघ में, एक सदस्य नहीं लिख रहा है और फिर एक और गिनती को अपरिभाषित व्यवहार के रूप में पढ़ रहा है?

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

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

return result; 

कोई अलियासिंग उल्लंघन:

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

कुछ [अनाज] (https://uscilab.github.io/cereal/) है और इसके बारे में चिंता न करें। – nwp

+0

मेरे पास पॉइंटर्स और एलियासिंग पर एक भाषा वकील उत्तर है (http://stackoverflow.com/a/12615861/726300), लेकिन एक चेतावनी के रूप में यह मानक में एक भूरा क्षेत्र है। यह भविष्य में सुधार किया जाना चाहिए, लेकिन मुझे किस दिशा में कोई जानकारी नहीं है। आपका प्रोग्राम [tweaked] हो सकता है (http://coliru.stacked-crooked.com/a/1207492fe8779748) तर्कसंगत रूप से पत्र के नियमों का पालन करने के लिए, लेकिन मैं यह नहीं कह सकता कि संकलक सहमत होंगे या नहीं। कम से कम जीसीसी अब शिकायत नहीं करता है, लेकिन ऐसा इसलिए हो सकता है क्योंकि हमने इसके अलियासिंग विश्लेषण को भ्रमित कर दिया है। दुख की बात है कि मेरे पास उचित उत्तर देने का समय नहीं है। –

+0

@ ल्यूकडैंटन: मुझे नहीं लगता कि ['std :: launder'] (http://en.cppreference.com/w/cpp/utility/launder) ओपी की इच्छा प्रदान करता है। –

उत्तर

6

यह क्या आप चाहते हैं। यदि आप T चाहते हैं, तो आपको T होना चाहिए। यदि आपका प्रकार छोटा रूप से कॉपी करने योग्य है, तो उम्मीद है कि यह भी मामूली रूप से रचनात्मक है और इसकी कोई कीमत नहीं है। किसी भी घटना में, आपको रिटर्न ऑपरेंड को फंक्शन रिटर्न वैल्यू में कॉपी करना होगा, और वह प्रतिलिपि बनाई गई है, इसलिए यहां वास्तव में कोई अतिरिक्त लागत नहीं है।

+1

प्रश्न 'टी' के निर्माण के बिना इसे करने के बारे में स्पष्ट रूप से पूछा गया। – nwp

+3

@nwp: हाँ, सवाल इसके बारे में गलत है। –

+0

क्या 'परिणाम' के पते को 'char *' में डालने में कोई बात है? – user2079303

1

आप std::aligned_storage क्लास टेम्पलेट का उपयोग करना चाहते हैं। यह इस सटीक समस्या को संभालने के लिए डिज़ाइन किया गया है। यहां आपके प्रश्न में आपके चेक के आधार पर कुछ SFINAE के साथ एक नमूना समाधान है।

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

यह अभी भी यूबी है, है ना? 'Aligned_storage' का उद्देश्य एक अलग है। –

+0

यह नहीं होना चाहिए। http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf – Andrew

+0

रिटर्न प्रकार के संदर्भ में कोई गैर-कॉन्स्ट अस्थायी संदर्भ क्यों लौटाएगा? : 'reinterpret_cast (गंतव्य)' -> टी – sandthorn

संबंधित मुद्दे