C ++ नया int [0] - क्या यह मेमोरी आवंटित करेगा?


241

एक साधारण परीक्षण ऐप:

cout << new int[0] << endl;

आउटपुट:

0x876c0b8

तो ऐसा लगता है कि यह काम करता है। इस बारे में मानक क्या कहता है? क्या यह हमेशा स्मृति के खाली ब्लॉक को "आवंटित" करने के लिए कानूनी है?


4
+1 बहुत दिलचस्प सवाल - हालांकि मुझे यकीन नहीं है कि यह वास्तविक कोड में कितना मायने रखता है।
ज़िफ्रे

37
@Zifre: मैं जिज्ञासा के लिए पूछ रहा हूं, लेकिन यह वास्तविक दुनिया में महत्वपूर्ण हो सकता है, उदाहरण के लिए जब आवंटित मेमोरी ब्लॉकों के आकार की गणना किसी तरह से की जाती है, और गणना का परिणाम शून्य हो सकता है, तो अपवाद जोड़ने की कोई प्रत्यक्ष आवश्यकता नहीं है। शून्य आकार ब्लॉक आवंटित नहीं करने के लिए .. क्योंकि उन्हें त्रुटियों के बिना आवंटित किया जाना चाहिए और हटा दिया जाना चाहिए (यदि केवल शून्य आकार का ब्लॉक ही नहीं है)। तो आमतौर पर यह एक मेमोरी ब्लॉक क्या है की व्यापक अमूर्तता देता है।

2
@ emg-2: आपके उदाहरण की स्थिति में, यह वास्तव में मायने नहीं रखेगा, क्योंकि हटाना [] पूरी तरह से एक NULL पॉइंटर :-) पर कानूनी है।
इवान टेरान

2
यह केवल मूर्त रूप से संबंधित है - इसलिए मैं यहां टिप्पणी कर रहा हूं - लेकिन सी ++ कई मायनों में सुनिश्चित करता है कि अलग-अलग वस्तुओं के अद्वितीय पते हैं ... भले ही उन्हें स्पष्ट रूप से भंडारण की आवश्यकता न हो। एक संबंधित प्रयोग एक खाली संरचना के आकार की जांच करने के लिए होगा। या उस संरचना की एक सरणी।
ड्रू डॉर्मन

2
शमोप्टी की टिप्पणी पर विस्तार से बताने के लिए: विशेषकर जब टेम्प्लेट के साथ प्रोग्रामिंग (उदाहरण के लिए नीति वर्ग टेम्पलेट जैसे std :: एलोकेटर), तो यह C ++ में शून्य आकार की वस्तुओं के लिए आम है। जेनेरिक कोड को ऑब्जेक्ट आइडेंटिटी की तुलना करने के लिए ऐसी वस्तुओं को गतिशील रूप से आवंटित करने और पॉइंटर्स का उपयोग करने की आवश्यकता हो सकती है। यही कारण है कि ऑपरेटर नया () शून्य-आकार के अनुरोधों के लिए अद्वितीय संकेत देता है। यकीनन कम महत्वपूर्ण / सामान्य, एक ही तर्क सरणी आवंटन और ऑपरेटर नए [] () पर लागू होता है।
ट्रेवर रॉबिन्सन

जवाबों:


233

5.3.4 / 7 से

जब एक प्रत्यक्ष-नए-घोषणाकर्ता में अभिव्यक्ति का मूल्य शून्य होता है, तो आवंटन फ़ंक्शन को कोई तत्व के साथ एक सरणी आवंटित करने के लिए कहा जाता है।

3.7.3.1/2 से

शून्य आकार के लिए एक अनुरोध के रूप में लौटे एक सूचक को निष्क्रिय करने का प्रभाव अपरिभाषित है।

भी

भले ही अंतरिक्ष का आकार [नए द्वारा] शून्य हो, अनुरोध विफल हो सकता है।

इसका मतलब है कि आप इसे कर सकते हैं, लेकिन आप कानूनी तौर पर (सभी प्लेटफार्मों पर अच्छी तरह से परिभाषित तरीके से) मेमोरी को निष्क्रिय नहीं कर सकते हैं जो आपको मिलती है - आप इसे केवल सरणी डिलीट करने के लिए पास कर सकते हैं - और आपको इसे हटाना चाहिए।

यहां एक दिलचस्प फुट-नोट (यानी मानक का एक आदर्श हिस्सा नहीं है, लेकिन एक्सपोजर प्रयोजनों के लिए शामिल है) 3.7.3.1/2 से वाक्य से जुड़ा हुआ है

[32। आशय यह है कि मॉलॉक () या कॉलोक () कॉल करके ऑपरेटर नया () लागू करने योग्य है, इसलिए नियम काफी हद तक समान हैं। C ++ एक गैर-शून्य पॉइंटर वापस करने के लिए शून्य अनुरोध की आवश्यकता में C से अलग है।]


यदि मुझे डिलीट नहीं किया गया तो मुझे मेमोरी लीक हो जाती है। क्या यह अपेक्षित है? कम से कम मुझे उम्मीद नहीं थी।
EralpB

12
@EralpB: इसके विपरीत, भले ही आपका अनुरोध शून्य हो, यह आवंटन हीप पर होता है, जहां एक अनुरोध का अर्थ है कि आवंटन को देखते हुए और आवंटन के बाद दिए गए ज़ोन के पहले और बाद में हीप रक्षकों को आवंटित और आरंभ करना, जैसे कई किताबों के संचालन को बनाए रखना। अन्य जटिल भयानक संरचनाएँ। इसे मुक्त करने का अर्थ है पिछड़े बहीखाते करना।
v.oddou

3
@EralpB हां मुझे लगता है कि आप हर बार जब आप new[]एक delete[]- जो भी आकार के साथ संतुलन नहीं रखते हैं, एक मेमोरी लीक होने की उम्मीद कर सकते हैं । विशेष रूप से, जब आप कॉल करते हैं, तो आपको new[i]उससे थोड़ी अधिक मेमोरी की आवश्यकता होती है, जिसे आप सरणी के आकार को संग्रहीत करने के लिए delete[]आवंटित करने की कोशिश कर रहे हैं (जो बाद में
डील

24

हां, इस तरह से शून्य-आकार की सरणी आवंटित करना कानूनी है। लेकिन आपको इसे हटाना भी होगा।


1
क्या आपके पास इसके लिए एक प्रशस्ति पत्र है? हम सभी जानते हैं कि int ar[0];अवैध क्यों है नया ठीक है?
मत्ती

4
यह दिलचस्प है कि शून्य आकार वस्तुओं को मना करने के साथ सी ++ इतना मजबूत नहीं है। खाली बेस क्लास ऑप्टिमाइज़ेशन के बारे में सोचें: यहाँ भी, एक खाली बेस क्लास सब-ऑब्जेक्ट का साइज़ जीरो हो सकता है। इसके विपरीत, सी स्टैंडर्ड यह सुनिश्चित करने के लिए एक मजबूत प्रयास करता है कि शून्य आकार की वस्तुएं कभी नहीं बनाई जाती हैं: मॉलॉक (0) को परिभाषित करते हुए यह कहता है कि प्रभाव कुछ गैर-शून्य तर्क के साथ मॉलॉक चलाने का है, उदाहरण के लिए। और संरचना में {...; टी एन []; }; जब सरणी (FAM) के लिए कोई स्थान आवंटित नहीं होता है, तो यह कहता है कि यह व्यवहार करता है जैसे कि "n" में एक तत्व है। (दोनों ही मामलों में, किसी भी तरह से ऑब्जेक्ट का उपयोग करना यूबी है, जैसे xn [0])
जोहान्स शहाब -

1
मुझे लगता sizeof (type)है कि शून्य वापस कभी नहीं आने की उम्मीद है। उदाहरण के लिए देखें: stackoverflow.com/questions/2632021/can-sizeof-return-0-zero
pqnet

यहां तक ​​कि तथाकथित "खाली आधार वर्ग अनुकूलन" केवल एक आग्रह के कारण प्रासंगिक है कि सभी वस्तुओं (जैसा कि वस्तुओं के भीतर सभी बाइट्स के विपरीत) में अद्वितीय पते होने चाहिए। C ++ को सरल बनाया जा सकता था यदि कोड जो वास्तव में अद्वितीय पते वाले ऑब्जेक्ट के बारे में परवाह करता था, यह सुनिश्चित करने के लिए आवश्यक था कि उनके पास गैर-शून्य आकार था।
सुपरकैट

15

इस बारे में मानक क्या कहता है? क्या यह हमेशा स्मृति के खाली ब्लॉक को "आवंटित" करने के लिए कानूनी है?

प्रत्येक वस्तु की एक विशिष्ट पहचान होती है, अर्थात एक अद्वितीय पता, जिसका अर्थ है एक गैर-शून्य लंबाई (स्मृति की वास्तविक मात्रा चुपचाप बढ़ जाएगी, यदि आप शून्य बाइट्स के लिए पूछें)।

यदि आपने इनमें से एक से अधिक वस्तुओं का आवंटन किया है, तो आप पाएंगे कि उनके अलग-अलग पते हैं।


"प्रत्येक वस्तु की एक विशिष्ट पहचान होती है, अर्थात एक अद्वितीय पता, जिसका अर्थ है एक गैर-शून्य लंबाई" - सही, लेकिन गलत। ऑब्जेक्ट का पता है, लेकिन ऑब्जेक्ट के लिए सूचक यादृच्छिक मेमोरी को इंगित कर सकता है। "मेमोरी की वास्तविक मात्रा चुपचाप बढ़ जाएगी, यदि आप शून्य बाइट्स के लिए पूछते हैं" - निश्चित नहीं। operator []सरणी के आकार को भी कहीं संग्रहीत करता है (देखें isocpp.org/wiki/faq/freestore-mgmt#num-elems-in-new-array )। इसलिए यदि कार्यान्वयन डेटा के साथ बाइट काउंट को आवंटित करता है, तो यह केवल बाइट काउंट और डेटा के लिए 0 बाइट्स के लिए आवंटित कर सकता है, 1-पास्ट-लास्ट पॉइंटर लौटाता है।
स्टीड

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

1
मानक ( open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf ) वास्तव में कहता है (3.7.4.1/2) कि अलग-अलग कॉल विभिन्न बिंदुओं operator new[]को वापस करने के लिए होनी चाहिए। BTW, के new expressionकुछ अतिरिक्त नियम (5.3.4) हैं। मुझे ऐसा कोई सुराग नहीं मिला कि new0 आकार के साथ वास्तव में कुछ भी आवंटित करने की आवश्यकता हो। क्षमा करें, मैंने अस्वीकार कर दिया क्योंकि मुझे पता है कि आपका उत्तर प्रश्नों का उत्तर नहीं दे रहा है, लेकिन कुछ विवादास्पद बयान दे रहा है।
स्टीड

@ ब्लॉक की लेन को स्टोर करने के लिए मेमोरी मेमोरी को एड्रेस स्पेस का उपयोग करके अनुमानित रूप से गणना की जा सकती है। उदाहरण के लिए शून्य-आकार के सरणियों के लिए यह संभव हो सकता है कि new[]किसी सीमा में पते वापस करने के लिए कार्यान्वयन हो, जहां कोई डायनामिक मेमोरी मैप नहीं है, इसलिए वास्तव में किसी भी मेमोरी का उपयोग नहीं करना है (पता स्थान का उपयोग करते समय)
pqnet

@pqnet: एक अच्छी गुणवत्ता कार्यान्वयन को असीमित संख्या में नए / हटाए गए चक्रों की अनुमति देनी चाहिए, क्या ऐसा नहीं करना चाहिए? 64-बिट पॉइंटर्स वाले प्लेटफ़ॉर्म पर यह कहना उचित होगा कि while(!exitRequested) { char *p = new char[0]; delete [] p; }रिसाइकलिंग पॉइंट्स के बिना लूप निष्पादित करने वाला कंप्यूटर संभवतः धूल में गिर जाएगा, इससे पहले कि वह संभवतः एड्रेस स्पेस से बाहर निकल जाए, लेकिन 32-बिट पॉइंटर्स वाले प्लेटफ़ॉर्म पर एक बहुत कम उचित धारणा।
सुपरकैट

14

हां इसके 0साथ आकार ब्लॉक आवंटित करना पूरी तरह से कानूनी है new। आप बस इसके साथ कुछ भी उपयोगी नहीं कर सकते हैं क्योंकि आपके पास पहुंचने के लिए कोई वैध डेटा नहीं है। int[0] = 5;गैरकानूनी है।

हालांकि, मेरा मानना ​​है कि मानक चीजों malloc(0)को वापस करने की अनुमति देता है NULL

आपको अभी भी delete []जो भी सूचक आपको आवंटन से वापस मिलेगा, उसकी आवश्यकता होगी ।


5
मॉलोक के बारे में, आप सही हैं - यह कार्यान्वयन परिभाषित है। इसे अक्सर मिसफिट के रूप में देखा जाता है।

मुझे लगता है कि एक दिलचस्प सवाल यह है: क्या 0 के आकार को देखते हुए नए रिटर्न का नोट्रो संस्करण नहीं हो सकता है?
इवान टेरान

1
नए और मॉलोक के शब्दार्थ किसी भी तरह से नहीं जुड़े हैं, कम से कम मानक द्वारा।

वे नहीं कह रहे हैं ... विशेष रूप से नए के nothrow संस्करण के बारे में पूछ रहे थे।
इवान टेरान

@ इवान - नए रिटर्न का nothrow संस्करण केवल तभी शून्य हो जाता है जब अनुरोध विफल हो जाता है - न कि केवल यदि अनुरोध का आकार 0 @ शून्य है - तो मानक रूप से जुड़ा हुआ नहीं है - लेकिन इरादे से जुड़ा हुआ है (यानी ऑपरेटर नया मालॉक के संदर्भ में लागू किया जा सकता है, लेकिन अन्य नहीं रास्ते के आसपास) - मेरे जवाब में शामिल फुटनोट देखिए
फैसल वली

1

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

मैंने पाया कि प्रभावी C ++ थर्ड एडिशन ने इस तरह कहा "आइटम 51: नए लिखने के दौरान सम्मेलन का पालन करें और हटाएं"।


0

मैं आपको गारंटी देता हूं कि नए int [0] के बाद से आपने इसका परीक्षण किया है।

उदाहरण के लिए, का मेमोरी उपयोग

int **arr = new int*[1000000000];

से काफी छोटा है

int **arr = new int*[1000000000];
for(int i =0; i < 1000000000; i++) {
    arr[i]=new int[0];
}

दूसरे कोड स्निपेट माइनस का पहला कोड स्निपेट का मेमोरी उपयोग कई नए int [0] के लिए उपयोग की जाने वाली मेमोरी है।

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