असंगठित सदस्यों के साथ संरचनाओं की नकल करना


29

क्या किसी ऐसे ढांचे की नकल करना मान्य है जिसके कुछ सदस्य आरम्भिक नहीं हैं?

मुझे संदेह है कि यह अपरिभाषित व्यवहार है, लेकिन यदि ऐसा है, तो यह किसी भी असंगठित सदस्यों को एक संरचना में छोड़ देता है (भले ही उन सदस्यों को कभी भी सीधे इस्तेमाल नहीं किया जाता है) काफी खतरनाक है। इसलिए मुझे आश्चर्य है कि क्या मानक में कुछ है जो इसे अनुमति देता है।

उदाहरण के लिए, क्या यह मान्य है?

struct Data {
  int a, b;
};

int main() {
  Data data;
  data.a = 5;
  Data data2 = data;
}

मुझे याद है कि कुछ समय पहले इसी तरह का सवाल था, लेकिन वह नहीं मिला। इस सवाल के रूप में है से संबंधित है यह एक
1201ProgramAlarm

जवाबों:


23

हां, यदि असंगठित सदस्य एक अहस्ताक्षरित संकीर्ण चरित्र प्रकार नहीं है std::byte, या फिर इस अनिश्चित अनिश्चित मान वाले एक संरचना की नकल करना, जो कि स्पष्ट रूप से परिभाषित कॉपी निर्माता के साथ तकनीकी रूप से अपरिभाषित व्यवहार है, क्योंकि यह एक चर को उसी प्रकार के अनिश्चित मूल्य के लिए कॉपी करने के लिए है, क्योंकि की [dcl.init] / 12

यह यहां लागू होता है, क्योंकि अंतर्निहित जनरेट कॉपी कंस्ट्रक्टर, एस को छोड़कर union, प्रत्येक सदस्य को व्यक्तिगत रूप से कॉपी करने के लिए परिभाषित किया जाता है जैसे कि प्रत्यक्ष-आरंभीकरण द्वारा, [class.copy.ctor] / 4 देखें

यह सक्रिय सीडब्ल्यूजी मुद्दे 2264 का विषय भी है ।

मुझे लगता है कि व्यवहार में आपको इसके साथ कोई समस्या नहीं होगी, हालांकि।

यदि आप 100% सुनिश्चित होना चाहते हैं, तो std::memcpyसदैव अच्छी तरह से परिभाषित व्यवहार का उपयोग करें यदि प्रकार तुच्छ रूप से प्रतिलिपि योग्य है , भले ही सदस्यों का अनिश्चित मूल्य हो।


इन मुद्दों को एक तरफ, आपको हमेशा अपने कक्षा के सदस्यों को निर्माण पर एक निर्दिष्ट मूल्य के साथ ठीक से इनिशियलाइज़ करना चाहिए, यह मानते हुए कि आपको क्लास को एक तुच्छ डिफ़ॉल्ट कंस्ट्रक्टर की आवश्यकता नहीं है । आप डिफ़ॉल्ट सदस्य आरंभीकृत सिंटैक्स का उपयोग करके आसानी से कर सकते हैं जैसे सदस्यों को मूल्य-आरंभ करना:

struct Data {
  int a{}, b{};
};

int main() {
  Data data;
  data.a = 5;
  Data data2 = data;
}

अच्छा .. वह ढांचा POD नहीं है (सादा पुराना डेटा)? इसका मतलब है कि सदस्यों को डिफ़ॉल्ट मानों के साथ आरंभ किया जाएगा? यह एक संदेह है
केविन कॉकेट्सू

क्या यह इस मामले में उथली प्रति नहीं है? इसके साथ क्या गलत हो सकता है जब तक कि नकल किए गए ढांचे में असंगठित सदस्य तक पहुंच न हो?
ट्रूथसेकर

@KevinKouketsu मैंने उस मामले के लिए एक शर्त जोड़ी है जहां एक तुच्छ / POD प्रकार की आवश्यकता होती है।
अखरोट

@TruthSeeker मानक कहता है कि यह अपरिभाषित व्यवहार है। इसका कारण आम तौर पर (गैर-सदस्यीय) चर के लिए अपरिभाषित व्यवहार होता है जो एंड्रीसेमशेव द्वारा उत्तर में समझाया गया है। मूल रूप से यह अनैतिक स्मृति के साथ ट्रैप अभ्यावेदन का समर्थन करना है। क्या यह स्ट्रक्चर्स के अंतर्निहित कॉपी निर्माण पर लागू करने का इरादा है, यह जुड़े सीडब्ल्यूजी मुद्दे का सवाल है।
अखरोट

@TruthSeeker प्रत्यारोपित कॉपी कंस्ट्रक्टर को प्रत्येक सदस्य को व्यक्तिगत रूप से कॉपी करने के लिए परिभाषित किया जाता है जैसे कि प्रत्यक्ष आरंभीकरण द्वारा। यह वस्तु प्रतिनिधित्व की नकल करने के लिए परिभाषित नहीं है memcpy, जैसे कि , यहां तक ​​कि तुच्छ रूप से प्रतिलिपि योग्य प्रकारों के लिए भी। एकमात्र अपवाद यूनियनों हैं, जिसके लिए निहित प्रतिलिपि निर्माता ऑब्जेक्ट प्रतिनिधित्व को कॉपी करता है जैसे कि memcpy
अखरोट

11

सामान्य तौर पर, अनइंस्टॉल किए गए डेटा की प्रतिलिपि बनाना अपरिभाषित व्यवहार है क्योंकि यह डेटा एक फंसाने की स्थिति में हो सकता है। इस पृष्ठ का उद्धरण :

यदि कोई ऑब्जेक्ट प्रतिनिधित्व ऑब्जेक्ट प्रकार के किसी भी मूल्य का प्रतिनिधित्व नहीं करता है, तो इसे ट्रैप प्रतिनिधित्व के रूप में जाना जाता है। वर्ण प्रकार की एक अभिव्यक्ति के माध्यम से इसे पढ़ने के अलावा किसी भी तरह से एक जाल प्रतिनिधित्व तक पहुंच अपरिभाषित व्यवहार है।

सिग्नलिंग NaN फ़्लोटिंग पॉइंट प्रकारों के लिए संभव है, और कुछ प्लेटफार्मों पर पूर्णांक में ट्रैप अभ्यावेदन हो सकते हैं

हालांकि, तुच्छ रूपmemcpy से प्रतिलिपि योग्य प्रकारों के लिए, वस्तु के कच्चे प्रतिनिधित्व की प्रतिलिपि बनाना संभव है । ऐसा करना सुरक्षित है क्योंकि ऑब्जेक्ट के मूल्य की व्याख्या नहीं की जाती है, और इसके बजाय ऑब्जेक्ट प्रतिनिधित्व के कच्चे बाइट अनुक्रम की प्रतिलिपि बनाई जाती है।


उन सभी प्रकार के डेटा के बारे में क्या जिनके लिए सभी बिट पैटर्न मान्य मानों (जैसे 64-बाइट संरचना युक्त unsigned char[64]) का प्रतिनिधित्व करते हैं ? अनिर्दिष्ट मूल्यों के रूप में एक संरचना के बाइट्स का इलाज करना अनावश्यक रूप से अनुकूलन को बाधित कर सकता है, लेकिन प्रोग्रामर को बेकार मान के साथ सरणी को मैन्युअल रूप से पॉप्युलेट करने की आवश्यकता होती है, इससे दक्षता और भी अधिक बढ़ जाएगी।
सुपरकैट

डेटा को प्रारंभ करना बेकार नहीं है, यह यूबी को रोकता है, चाहे यह ट्रैप अभ्यावेदन के कारण हो या बाद में अनइंस्टॉल किए गए डेटा का उपयोग करके। 64 बाइट्स (1 या 2 कैश लाइन) को शून्य करना उतना महंगा नहीं है जितना यह लग सकता है। और अगर आपके पास बड़ी संरचनाएं हैं जहां यह महंगा है, तो आपको उन्हें कॉपी करने से पहले दो बार सोचना चाहिए। और मुझे पूरा यकीन है कि आपको किसी न किसी बिंदु पर उन्हें आरंभ करना होगा।
एंड्री सेमशेव

मशीन कोड संचालन जो संभवतः एक कार्यक्रम के व्यवहार को प्रभावित नहीं कर सकते हैं बेकार हैं। यह धारणा कि मानक द्वारा यूबी के रूप में वर्णित किसी भी कार्रवाई को हर कीमत पर टाला जाना चाहिए, बल्कि यह कहना कि [सी मानक समिति के शब्दों में] यूबी "संभावित अनुरूप भाषा विस्तार के क्षेत्रों की पहचान करता है", तुलनात्मक रूप से हाल ही में है। हालांकि मैंने C ++ मानक के लिए प्रकाशित राशनले को नहीं देखा है, यह स्पष्ट रूप से इस बात पर अधिकार देता है कि C ++ कार्यक्रमों को अनुरूप या गैर-अनुरूपता के रूप में वर्गीकृत करने से इनकार करने से क्या करने की अनुमति है, जिसका अर्थ है कि यह समान एक्सटेंशन की अनुमति देगा।
सुपरकैट

-1

कुछ मामलों में, जैसे कि एक वर्णित है, सी ++ मानक कंपाइलरों को उस प्रक्रिया का निर्माण करने की अनुमति देता है, जो उनके ग्राहकों को सबसे अधिक उपयोगी लगेगी, उस व्यवहार की भविष्यवाणी किए बिना। दूसरे शब्दों में, ऐसे निर्माण "अपरिभाषित व्यवहार" का आह्वान करते हैं। हालांकि, इसका मतलब यह नहीं है कि इस तरह के निर्माण को "मना" किया जाता है क्योंकि C ++ मानक स्पष्ट रूप से अधिकार क्षेत्र को माफ करता है कि गठित कार्यक्रमों को क्या करने की अनुमति है। हालांकि मैं C ++ मानक के लिए किसी भी प्रकाशित किए गए राशन दस्तावेज़ से अनजान हूं, लेकिन यह तथ्य यह है कि यह C89 की तरह अपरिभाषित व्यवहार का वर्णन करता है, जिसका अर्थ होगा कि इसका अर्थ समान है: "अपरिभाषित व्यवहार कार्यान्वयनकर्ता को कुछ विशिष्ट त्रुटियों को पकड़ने के लिए लाइसेंस नहीं देता है जो कठिन हैं। जाँच द्वारा पता करना।

ऐसी कई स्थितियाँ हैं जहाँ किसी चीज़ को संसाधित करने का सबसे कुशल तरीका एक संरचना के कुछ हिस्सों को लिखना होगा जिसमें डाउनस्ट्रीम कोड के बारे में ध्यान रखना होगा, जबकि उन डाउन-कोड के बारे में परवाह नहीं करना है। आवश्यक है कि कार्यक्रम एक संरचना के सभी सदस्यों को आरम्भिक कर दें, जिनमें यह भी शामिल है कि जिनके बारे में कभी भी ध्यान नहीं दिया जाएगा, वे अनावश्यक रूप से दक्षता को बाधित करेंगे।

इसके अलावा, कुछ परिस्थितियां ऐसी हैं जहां गैर-नियतात्मक फैशन में गैर-व्यवस्थित डेटा व्यवहार करना सबसे अधिक कुशल हो सकता है। उदाहरण के लिए, दिया गया:

struct q { unsigned char dat[256]; } x,y;

void test(unsigned char *arr, int n)
{
  q temp;
  for (int i=0; i<n; i++)
    temp.dat[arr[i]] = i;
  x=temp;
  y=temp;
}

यदि डाउनस्ट्रीम कोड किसी ऐसे तत्व के मूल्यों की परवाह नहीं करेगा x.datया y.datजिसके सूचकांक में सूचीबद्ध नहीं थे arr, तो कोड को इसके लिए अनुकूलित किया जा सकता है:

void test(unsigned char *arr, int n)
{
  q temp;
  for (int i=0; i<n; i++)
  {
    int it = arr[i];
    x.dat[index] = i;
    y.dat[index] = i;
  }
}

दक्षता में यह सुधार तब संभव नहीं होगा जब प्रोग्रामर को temp.datकॉपी करने से पहले उन डाउनस्ट्रीम सहित हर तत्व को स्पष्ट रूप से लिखना आवश्यक नहीं होगा।

दूसरी ओर, कुछ एप्लिकेशन हैं जहां डेटा रिसाव की संभावना से बचना महत्वपूर्ण है। ऐसे अनुप्रयोगों में, या तो कोड का एक संस्करण उपयोगी हो सकता है, जो कि बिना डाउनस्ट्रीम कोड को देखे, या बिना कार्यान्वयन गारंटी के किसी भी भंडारण के लिए उपयोगी हो सकता है, इस संबंध में बिना किसी अनैतिक भंडारण को कॉपी करने के किसी भी प्रयास को फंसाने का साधन है। जिनकी सामग्री लीक हो सकती है, उन्हें शून्य या अन्यथा गैर-गोपनीय डेटा के साथ अधिलेखित कर दिया जाएगा।

मैं जो बता सकता हूं, उसमें से C ++ मानक यह कहने का कोई प्रयास नहीं करता है कि इनमें से कोई भी व्यवहार अनिवार्य रूप से दूसरे की तुलना में अधिक उपयोगी है ताकि इसे अनिवार्य ठहराया जा सके। विडंबना यह है कि विनिर्देशन की इस कमी का उद्देश्य अनुकूलन की सुविधा प्रदान करना हो सकता है, लेकिन यदि प्रोग्रामर किसी भी तरह की कमजोर व्यवहार संबंधी गारंटी का फायदा नहीं उठा सकते हैं, तो किसी भी अनुकूलन को नकार दिया जाएगा।


-2

चूंकि सभी सदस्य Dataआदिम प्रकार के हैं, इसलिए सभी सदस्यों के data2"बिट-बाय-बिट कॉपी" प्राप्त करेंगे data। तो का मूल्य data2.bबिल्कुल उसी के मूल्य के समान होगा data.b। हालाँकि, सटीक मूल्य की data.bभविष्यवाणी नहीं की जा सकती है, क्योंकि आपने इसे स्पष्ट रूप से शुरू नहीं किया है। यह के लिए आवंटित स्मृति क्षेत्र में बाइट्स के मूल्यों पर निर्भर करेगा data


क्या आप मानक के संदर्भ में इसका समर्थन कर सकते हैं? @Wnut द्वारा दिए गए लिंक का अर्थ है कि यह अपरिभाषित व्यवहार है। क्या मानक में POD के लिए कोई अपवाद है?
टोमेक कज्जाका

हालांकि निम्नलिखित मानक से लिंक नहीं है, फिर भी: en.cppreference.com/w/cpp/language/… "" त्रिविम रूप से ऑब्जेक्ट्स को अपने ऑब्जेक्ट प्रतिनिधित्वों को मैन्युअल रूप से कॉपी करके कॉपी किया जा सकता है, जैसे कि std :: memmove। C के साथ संगत सभी प्रकार। भाषा (POD प्रकार) तुच्छ रूप से प्रतिलिपि योग्य हैं। "
ivan.ukr

इस मामले में केवल "अपरिभाषित व्यवहार" यह है कि हम असंगठित सदस्य चर के मूल्य की भविष्यवाणी नहीं कर सकते। लेकिन कोड संकलन और सफलतापूर्वक चलता है।
ivan.ukr

1
आप जो उद्धरण उद्धृत करते हैं, वह मेम्मोव के व्यवहार के बारे में बात करता है, लेकिन यह वास्तव में यहां प्रासंगिक नहीं है क्योंकि मेरे कोड में मैं कॉपी कंस्ट्रक्टर का उपयोग कर रहा हूं, मेमोव का नहीं। अन्य उत्तर का अर्थ है कि कॉपी कंस्ट्रक्टर के उपयोग से अपरिभाषित व्यवहार होता है। मुझे लगता है कि आप "अपरिभाषित व्यवहार" शब्द को भी गलत समझते हैं। इसका मतलब है कि भाषा बिल्कुल कोई गारंटी नहीं देती है, जैसे कि प्रोग्राम क्रैश हो सकता है या डेटा को यादृच्छिक रूप से या कुछ भी कर सकता है। इसका यह मतलब नहीं है कि कुछ मूल्य अप्रत्याशित है, यह अनिर्दिष्ट व्यवहार होगा।
टोमेक कज्जाका

@ ivan.ukr C ++ मानक निर्दिष्ट करता है कि अंतर्निहित कॉपी / मूव कन्स्ट्रक्टर्स सदस्य-वार कार्य करते हैं जैसे कि प्रत्यक्ष-आरंभीकरण द्वारा, मेरे उत्तर में लिंक देखें। इसलिए प्रतिलिपि निर्माण एक " " बिट-बाय-बिट कॉपी " " नहीं बनाता है । आप केवल संघ प्रकार है, जिसके लिए अंतर्निहित प्रतिलिपि निर्माता के लिए सही हैं है के रूप में अगर एक मैनुअल द्वारा वस्तु प्रतिनिधित्व कॉपी करने के लिए निर्दिष्ट । इसमें से कोई भी उपयोग करने से रोकता है या नहीं । यह केवल निहित कॉपी कंस्ट्रक्टर का उपयोग करने से रोकता है। std::memcpystd::memcpystd::memmove
अखरोट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.