2017-10-07 23 views
5

मान लीजिए कि T एक पीओडी प्रकार है जिसमें पॉइंटर नहीं होता है, और मैं टी को क्रमबद्ध करना चाहता हूं (कुछ अन्य डेटा के अलावा)। मैंने यह करने के लिए नीचे दिए गए फ़ंक्शंस बनाए हैं:क्या पीओडी डेटा को सीधे सर सरणी में कास्ट करके सुरक्षित करना सुरक्षित है?

template<class T> void serialize(const T& source, char*& dest) 
{ 
    *(T*)dest = source; 
    dest += sizeof(T); 
} 
template<class T> void deserialize(T& dest, char*& source) 
{ 
    dest = *(T*)source; 
    source += sizeof(T); 
} 

क्या इससे कोई समस्या हो सकती है, या क्या ऐसे कोई कंपाइलर्स हैं जहां यह काम नहीं करेगा? दूसरे शब्दों में, कोड होगा:

template<class T> bool check_sanity(const T& obj) 
{ 
    std::unique_ptr<char[]> buffer { new int[sizeof(T)] }; 
    serialize(obj, buffer); 
    T new_obj; 
    deserialize(new_obj, buffer); 
    return new_obj == obj; 
} 

कभी झूठी वापसी? (मान लें कि टी पीओडी है और कोई भी == ऑपरेटर ओवरलोड नहीं किया गया है)।

मैं एमपीआई के साथ संयोजन के लिए इन क्रमिकरण विधियों को लिख रहा हूं, जहां उनका उपयोग बहीखाता के लिए आवश्यक कुछ डेटा वितरित करने के लिए कार्यक्रम की शुरुआत में किया जाएगा, इसलिए एक ही कार्यक्रम हमेशा क्रमबद्ध और deserializing होगा डेटा।

+0

मुझे यकीन नहीं है कि आप सख्त-एलियासिंग नियमों को कैसे तोड़ रहे हैं क्योंकि 'टी *' 'char *' और 't *' पर वापस वैध होना चाहिए .. मैंने सोचा कि 'reinterpret_cast' क्या था .. – Brandon

उत्तर

2

मुझे कुछ समस्याएं दिखाई देती हैं। एक छोटी सी एक:

IIRC, इस अलियासिंग नियम उल्लंघन के कारण यूबी है, (char * किसी अन्य सूचक उर्फ ​​सकता है, लेकिन इसका मतलब यह है कि आप एक char * सूचक के माध्यम से किसी वस्तु का उपयोग कर सकते हैं, लेकिन नहीं उपाध्यक्ष प्रतिकूल, जैसा कि आपके उदाहरण में)।

दूसरे शब्दों में, कोड होगा: ... कभी झूठी वापसी?

शायद नहीं, लेकिन आपने केवल एक ही वस्तु को क्रमबद्ध करने का उल्लेख नहीं किया है।

std::unique_ptr<char[]> buffer { new char[sizeof(int) + 1] }; 
char x = 0; 
int y = 0; 
serialize(x, buffer); 
serialize(y, buffer); // may crash or write into wrong location 

दोषपूर्ण लाइन में ही है (लेकिन deserialize भी प्रभावित होता है):

*(T*)dest = source; // source is int, dest is not aligned 

संकलक कि गंतव्य समझेंगे ठीक से है

तो, बड़ी समस्या संरेखण है गठबंधन और गठबंधन स्टोर के लिए सीपीयू निर्देशों का उपयोग करें (एआरएम आर्किटेक्चर पर इससे वास्तविक समस्याएं पैदा होंगी)।

समाधान के बजाय memcpy उपयोग करने के लिए है:

memcpy(dest, &source, sizeof(T)); 

वहाँ प्रदर्शन के बारे में चिंता करने की जरूरत नहीं है। आधुनिक कंपाइलर्स ज्ञात आकारों के साथ वस्तुओं के memcpy अनुकूलित करने में सक्षम हैं।

+0

मैंने 'char *' के माध्यम से केवल पढ़ने के लिए अच्छी तरह परिभाषित होने के माध्यम से अलियासिंग के बारे में नहीं सुना है। क्या आपके पास कोई संदर्भ है? – HolyBlackCat

+0

मेरा बुरा। आप दोनों 'char *' पॉइंटर्स के माध्यम से ऑब्जेक्ट्स को पढ़ और लिख सकते हैं, लेकिन इसके विपरीत नहीं (यानी 'char * 'to' t * 'और इसे अस्वीकार करें)। –

1

*(T*)dest = source; एक सख्त अलियासिंग उल्लंघन है।

इसके बजाय आप लिखना चाहिए:

memcpy(dest, &source, sizeof source); 

आप पॉड कॉपी कर सकते हैं सफलतापूर्वक memcpy का उपयोग कर के आसपास वस्तुओं।

आपके check_sanity फ़ंक्शन में यह संकलित करने में विफल रहेगा, क्योंकि operator==T के लिए परिभाषित नहीं है।(कोई परोक्ष-उत्पन्न कर रहे हैं तुलना ऑपरेटरों)

0

हाँ, आप इसे जब तक बफर चार, अहस्ताक्षरित चार या std :: बाइट की एक सरणी है क्या कर सकते हैं, सी ++ मानक [basic.type]:

किसी भी ऑब्जेक्ट (बेस-क्लास सबबजेक्ट के अलावा) त्रिकोणीय रूप से कॉपी करने योग्य प्रकार टी के लिए, ऑब्जेक्ट को बनाने के लिए अंतर्निहित बाइट्स (4.4) ऑब्जेक्ट बनाने के लिए ऑब्जेक्ट को टी टाइप करने का मान्य मान है या नहीं, चार, हस्ताक्षरित चार, orstd :: बाइट (21.2.1) की सरणी। यदि उस सरणी की सामग्री ऑब्जेक्ट में वापस कॉपी की गई है, तो ऑब्जेक्ट इसके बाद उसका मूल मान रखेगा। [उदाहरण:

#define N sizeof(T) 
char buf[N]; 
T obj; //obj initialized to its original value 
std::memcpy(buf, &obj, N);// between these two calls to std::memcpy,obj might be modified 
std::memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar type holds its original value 

- अंत उदाहरण]

नोटा: बफर के संरेखण पर कोई आवश्यकता नहीं हैं।

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