C ++ में 'void * `का निहितार्थ क्यों नहीं है?


30

सी में, void *किसी भी अन्य पॉइंटर प्रकार को डालने की आवश्यकता नहीं है , इसे हमेशा सुरक्षित रूप से बढ़ावा दिया जाता है। हालाँकि, C ++ में, यह मामला नहीं है। उदाहरण के लिए,

int *a = malloc(sizeof(int));

C में काम करता है, लेकिन C ++ में नहीं। (नोट: मुझे पता है कि आपको mallocC ++ में या उस मामले के लिए उपयोग नहीं करना चाहिए new, और इसके बजाय स्मार्ट पॉइंटर्स और / और एसटीएल को प्राथमिकता देना चाहिए; यह विशुद्ध रूप से जिज्ञासा से पूछा गया है) C ++ मानक इस अंतर्निहित कलाकारों को अनुमति क्यों नहीं देता है, जबकि सी मानक करता है?


3
long *a = malloc(sizeof(int));उफ़, कोई केवल एक प्रकार बदलना भूल गया!
डोभाल

4
@ डोवाल: यह अभी भी आसानी से sizeof(*a)इसके बजाय का उपयोग करके तय किया गया है।
वुल्फपैके

3
मेरा मानना ​​है कि @ शाफ़्टफ़्रेक बिंदु यह है कि सी इस अंतर्निहित रूपांतरण का कारण है क्योंकि mallocआवंटित किए गए प्रकार के लिए एक पॉइंटर वापस नहीं किया जा सकता है। newक्या C ++ आवंटित प्रकार के लिए एक पॉइंटर लौटाता है, इसलिए ठीक से लिखा गया C ++ कोड कभी नहीं void *डाला जाएगा।
को रोबोट

3
एक तरफ के रूप में, यह कोई अन्य सूचक प्रकार नहीं है। केवल डेटा-पॉइंटर्स को लागू करने की आवश्यकता है।
डिडुप्लिकेटर

3
@ wolfPack88 आपका इतिहास गलत है। C ++ था void, C नहीं था । जब उस कीवर्ड / विचार को C में जोड़ा गया, तो उन्होंने इसे C की आवश्यकताओं के अनुरूप बदल दिया। यही कारण है कि शीघ्र ही था के बाद सूचक प्रकार की जाँच की जा रही शुरू कर दिया सब पर । देखें कि क्या आप K & R C वर्णन पुस्तिका ऑनलाइन प्राप्त कर सकते हैं, या वेइट ग्रुप के C प्राइमर जैसे C प्रोग्रामिंग टेक्स्ट की एक पुरानी कॉपी । ANSI C भरा हुआ था, C ++ से बैकपोर्टेड या प्रेरित फीचर्स की, और K & R C ज्यादा सरल था। इसलिए यह अधिक सही है कि C ++ विस्तारित C ​​के रूप में यह उस समय अस्तित्व में था, और जिस सी को आप जानते हैं वह C ++ से नीचे छीन लिया गया था।
JDługosz

जवाबों:


39

क्योंकि निहित प्रकार के रूपांतरण आमतौर पर असुरक्षित होते हैं, और C ++ टाइप करने के लिए C ++ से अधिक सुरक्षित रुख अपनाता है।

सी आमतौर पर निहित रूपांतरणों की अनुमति देगा, भले ही अधिकांश संभावना यह हो कि रूपांतरण एक त्रुटि है। ऐसा इसलिए है क्योंकि C मानता है कि प्रोग्रामर को ठीक से पता है कि वे क्या कर रहे हैं, और यदि नहीं, तो यह प्रोग्रामर की समस्या है, न कि कंपाइलर की समस्या की।

सी ++ आमतौर पर उन चीजों को अस्वीकार कर देगा जो संभावित रूप से त्रुटियां हो सकती हैं, और आपको एक प्रकार के कलाकारों के साथ अपने इरादे को स्पष्ट रूप से बताने की आवश्यकता होती है। ऐसा इसलिए है क्योंकि C ++ प्रोग्रामर-फ्रेंडली होने की कोशिश कर रहा है।

आप पूछ सकते हैं कि यह कैसे अनुकूल है जब यह वास्तव में आपको अधिक टाइप करने की आवश्यकता होती है।

ठीक है, आप देखते हैं, किसी भी प्रोग्रामिंग भाषा में, किसी भी कार्यक्रम में, किसी भी लाइन की कोड, आमतौर पर कई बार पढ़ी जाएगी (*)। इसलिए, पढ़ने में आसानी लेखन की तुलना में अधिक महत्वपूर्ण है। और पढ़ते समय, किसी भी संभावित असुरक्षित रूपांतरण को स्पष्ट प्रकार की जातियों के माध्यम से बाहर खड़ा करने से यह समझने में मदद मिलती है कि क्या चल रहा है और एक निश्चित स्तर है कि जो हो रहा है वह वास्तव में क्या होने का इरादा था।

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

(*) आदर्श रूप में यह केवल एक बार लिखा जाएगा, लेकिन यह हर बार पढ़ा जाएगा कि किसी को पुन: उपयोग के लिए इसकी उपयुक्तता का निर्धारण करने के लिए इसकी समीक्षा करने की आवश्यकता है, और हर बार समस्या निवारण चल रहा है, और हर बार किसी को इसके पास कोड जोड़ने की आवश्यकता होती है, और फिर हर बार पास के कोड की समस्या निवारण होता है, और इसी तरह। "लेखन-वन्स-वन, रन, फ़िर थ्रो" स्क्रिप्ट को छोड़कर सभी मामलों में यह सच है, और इसलिए यह कोई आश्चर्य नहीं है कि अधिकांश स्क्रिप्टिंग भाषाओं में एक वाक्यविन्यास है जो पढ़ने में आसानी के लिए पूर्ण उपेक्षा के साथ लिखने में आसानी की सुविधा देता है। कभी सोचा है कि पर्ल पूरी तरह से समझ से बाहर है? तुम अकेले नही हो। ऐसी भाषाओं को "केवल लिखने वाली" भाषा समझें।


C अनिवार्य रूप से मशीन कोड से एक कदम ऊपर है। मैं इस तरह की चीजों के लिए सी क्षमा कर सकता हूं।
किक्स

8
कार्यक्रम (भाषा जो भी हो) पढ़ने के लिए होती है। स्पष्ट संचालन बाहर खड़े हैं।
मैथ्यू एम।

10
यह ध्यान देने योग्य है, कि C ++ के माध्यम से जातियां अधिक असुरक्षित होती void*हैं , क्योंकि C ++ में कुछ OOP फीचर्स जिस तरह से कार्यान्वित किए जाते हैं, उसी प्रकार पॉइंटर को पॉइंटर प्रकार के आधार पर अलग-अलग मान हो सकते हैं।
हाइड

@MatthieuM। बिल्कुल सच। इसे जोड़ने के लिए धन्यवाद, यह उत्तर का हिस्सा होने के लायक है।
माइक नाकिस

1
@ मैथ्यूएमएम .: आह, लेकिन आप वास्तव में सब कुछ स्पष्ट रूप से नहीं करना चाहते हैं। पढ़ने के लिए अधिक होने से पठनीयता में वृद्धि नहीं होती है। हालांकि इस बिंदु में संतुलन स्पष्ट रूप से स्पष्ट होने के लिए है।
डिडुप्लीकेटर

28

यहाँ Stroustrup क्या कहते हैं :

C में, आप एक void * को T * में बदल सकते हैं। यह असुरक्षित है

फिर वह एक उदाहरण दिखाता है कि कैसे शून्य * खतरनाक हो सकता है और कहता है:

... नतीजतन, सी ++ में, शून्य से एक टी * प्राप्त करने के लिए * आपको एक स्पष्ट डाली की आवश्यकता है। ...

अंत में, उन्होंने नोट किया:

सी में इस असुरक्षित रूपांतरण के सबसे आम उपयोगों में से एक उपयुक्त पॉइंटर को मॉलोक () का परिणाम निर्दिष्ट करना है। उदाहरण के लिए:

int * p = malloc (sizeof (int));

C ++ में, टाइपसेफ़ नए ऑपरेटर का उपयोग करें:

int * p = new int;

वह C ++ के डिज़ाइन और इवोल्यूशन में इस पर बहुत अधिक विस्तार से जाते हैं ।

तो इसका उत्तर उबलता है: भाषा डिजाइनर का मानना ​​है कि यह एक असुरक्षित पैटर्न है, और इसलिए इसे अवैध बना दिया है और पैटर्न को सामान्य रूप से उपयोग करने के लिए पूरा करने के वैकल्पिक तरीके प्रदान किए हैं।


1
mallocउदाहरण से संबंधित , यह ध्यान देने योग्य है कि mallocइच्छाशक्ति (जाहिर है) एक निर्माता को नहीं बुलाती है, इसलिए यदि यह एक वर्ग प्रकार है जिसके लिए आप स्मृति आवंटित कर रहे हैं, तो वर्ग प्रकार को निहित करने में सक्षम होने के कारण भ्रामक होगा।
चबेकर0

यकीनन यह मेरा एक बहुत अच्छा जवाब है। मैं केवल "अधिकार से तर्क" दृष्टिकोण को नापसंद करता हूं।
माइक नाकिस

"नया int" - वाह, एक C ++ newbie के रूप में मुझे एक प्रकार के ढेर को जोड़ने के तरीके के बारे में सोचने में परेशानी हो रही थी, और मुझे नहीं पता था कि आप ऐसा कर सकते हैं। -1 मॉलोक के लिए उपयोग।
कटाना ३१४

3
@ माइक नाइकिसफीडब्ल्यूडब्ल्यू, मेरा इरादा आपके उत्तर का पूरक था। इस मामले में, सवाल यह था कि "उन्होंने ऐसा क्यों किया", इसलिए मुझे लगा कि मुख्य डिजाइनर से सुनवाई उचित है।
रोबोट

11

C में, शून्य * को किसी अन्य पॉइंटर प्रकार में डालने की आवश्यकता नहीं है, इसे हमेशा सुरक्षित रूप से प्रचारित किया जाता है।

यह हमेशा पदोन्नत किया जाता है, हाँ, लेकिन शायद ही सुरक्षित रूप से

C ++ इस व्यवहार को सटीक रूप से अक्षम करता है क्योंकि यह C से अधिक सुरक्षित प्रकार की प्रणाली का प्रयास करता है, और यह व्यवहार सुरक्षित नहीं है


रूपांतरण टाइप करने के लिए इन 3 दृष्टिकोणों पर सामान्य रूप से विचार करें:

  1. उपयोगकर्ता को सब कुछ लिखने के लिए मजबूर करते हैं, इसलिए सभी रूपांतरण स्पष्ट हैं
  2. मान लें कि उपयोगकर्ता जानता है कि वे क्या कर रहे हैं और किसी भी प्रकार को किसी अन्य में परिवर्तित कर सकते हैं
  3. टाइप-सेफ जेनरिक (टेम्प्लेट, नई-अभिव्यक्तियाँ), स्पष्ट उपयोगकर्ता-परिभाषित रूपांतरण ऑपरेटरों के साथ एक पूर्ण प्रकार की प्रणाली को लागू करना, और केवल संकलक द्वारा देखी जा सकने वाली चीजों के लिए स्पष्ट रूपांतरणों को बलपूर्वक सुरक्षित करना

ठीक है, 1 बदसूरत है और कुछ भी करने के लिए एक व्यावहारिक बाधा है, लेकिन वास्तव में इसका इस्तेमाल किया जा सकता है जहां बड़ी देखभाल की आवश्यकता होती है। C ने लगभग 2 को चुना, जिसे लागू करना आसान है, और 3 के लिए C ++, जिसे लागू करना कठिन है लेकिन सुरक्षित है।


यह 3 तक पहुंचने के लिए एक लंबी कठिन सड़क थी, अपवाद बाद में जोड़े गए और बाद में अभी भी टेम्पलेट।
19:30 पर JDługosz

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

1

परिभाषा के अनुसार, एक शून्य सूचक कुछ भी इंगित कर सकता है। किसी भी पॉइंटर को एक शून्य पॉइंटर में परिवर्तित किया जा सकता है और इस प्रकार, आप ठीक उसी मान पर पहुंचने में सक्षम होंगे। हालांकि, अन्य प्रकार के संकेत में बाधाएं हो सकती हैं, जैसे संरेखण प्रतिबंध। उदाहरण के लिए, एक ऐसी वास्तुकला की कल्पना करें जहां अक्षर किसी भी स्मृति पते पर कब्जा कर सकते हैं, लेकिन पूर्णांक भी पता सीमाओं पर शुरू होना चाहिए। कुछ आर्किटेक्चर में, पूर्णांक पॉइंटर्स एक बार में 16, 32 या 64 बिट्स की गणना कर सकते हैं ताकि स्मृति में एक ही स्थान की ओर इशारा करते हुए चार * वास्तव में int * के संख्यात्मक मान का एक से अधिक हो सकता है। इस मामले में, एक शून्य से परिवर्तित करना * वास्तव में बिट्स को गोल कर देगा जो पुनर्प्राप्त नहीं किया जा सकता है और इसलिए प्रतिवर्ती नहीं है।

सीधे शब्दों में कहें, शून्य पॉइंटर किसी भी चीज़ की ओर इशारा कर सकता है, जिसमें ऐसी चीज़ें शामिल हैं जो अन्य पॉइंटर्स इंगित करने में सक्षम नहीं हो सकते हैं। इस प्रकार, शून्य पॉइंटर के लिए रूपांतरण सुरक्षित है, लेकिन अन्य तरीके से नहीं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.