C ++ मानक का हिस्सा चर-लंबाई सरणियाँ क्यों नहीं हैं?


326

मैंने पिछले कुछ वर्षों में C का बहुत अधिक उपयोग नहीं किया है। जब मैंने इस प्रश्न को पढ़ा तो मैं कुछ सी सिंटैक्स में आया, जिससे मैं परिचित नहीं था।

C99 में स्पष्ट रूप से निम्नलिखित सिंटैक्स मान्य है:

void foo(int n) {
    int values[n]; //Declare a variable length array
}

यह एक बहुत उपयोगी सुविधा की तरह लगता है। क्या कभी इसे C ++ मानक में जोड़ने के बारे में चर्चा हुई, और यदि हां, तो इसे क्यों छोड़ दिया गया?

कुछ संभावित कारण:

  • संकलक विक्रेताओं के लिए बालों को लागू करने के लिए
  • मानक के कुछ अन्य भाग के साथ असंगत
  • अन्य C ++ कंस्ट्रक्शंस के साथ कार्यक्षमता का अनुकरण किया जा सकता है

C ++ मानक बताता है कि सरणी आकार एक स्थिर अभिव्यक्ति (8.3.4.1) होना चाहिए।

हां, निश्चित रूप से मुझे एहसास है कि खिलौना उदाहरण में कोई भी उपयोग कर सकता है std::vector<int> values(m);, लेकिन यह ढेर से मेमोरी को आवंटित करता है न कि स्टैक से। और अगर मुझे एक बहुआयामी सरणी की तरह चाहिए:

void foo(int x, int y, int z) {
    int values[x][y][z]; // Declare a variable length array
}

vectorसंस्करण बहुत अनाड़ी हो जाता है:

void foo(int x, int y, int z) {
    vector< vector< vector<int> > > values( /* Really painful expression here. */);
}

स्लाइस, रो और कॉलम भी संभवतः सभी मेमोरी में फैले होंगे।

चर्चा को देखते हुए comp.std.c++यह स्पष्ट है कि यह सवाल तर्क के दोनों पक्षों में कुछ बहुत ही भारी नामों के साथ विवादास्पद है। यह निश्चित रूप से स्पष्ट नहीं है कि std::vectorहमेशा एक बेहतर समाधान होता है।


3
जिज्ञासा से बाहर, इसे स्टैक पर आवंटित करने की आवश्यकता क्यों है? क्या आप ढेर आवंटन प्रदर्शन के मुद्दों से डरते हैं?
दिमित्री C.

32
@ दिमित्री वास्तव में नहीं है, लेकिन इस बात से इनकार नहीं किया जा सकता है कि ढेर आवंटन, ढेर आवंटन से तेज होगा। और कुछ मामलों में यह मामला हो सकता है।
एंड्रियास ब्रिंक

11
चर लंबाई सरणियों का मुख्य लाभ यह है कि जब आप इस सरणी के माध्यम से एक दूसरे के बगल में बाइट्स पढ़ते हैं और लिखते हैं तो सभी डेटा एक साथ बंद होते हैं। आपके डेटा को कैशे में लाया जाता है और सीपीयू बिना मेमोरी के / से बाइट्स भेजे और भेजकर इस पर काम कर सकता है।
कैलमेरियस

4
वैरिएबल लंबाई वाले सरणियों का उपयोग स्थैतिक स्थिरांक के साथ प्रीप्रोसेसर स्थिरांक को बदलने के लिए भी किया जा सकता है। सी में भी आपके पास वीएलए के लिए एक और विकल्प नहीं है, और इसे कभी-कभी पोर्टेबल सी / सी ++ कोड (दोनों कंपाइलर के साथ संगत) लिखने की आवश्यकता होती है।
यूरी

2
एक तरफ के रूप में, यह क्लैंग ++ वीएलए की अनुमति देता है।
user3426763

जवाबों:


204

हाल ही में usenet में इस बारे में चर्चा हुई: C ++ 0x में कोई वीएलएएएस क्यों नहीं

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

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

आप उपयोग कर सकते हैं std::vector, लेकिन यह काफी समान नहीं है, क्योंकि यह गतिशील मेमोरी का उपयोग करता है, और इसे अपने स्वयं के स्टैक-एलोकेटर का उपयोग करना आसान नहीं है (संरेखण एक मुद्दा है, भी)। यह भी एक ही समस्या का समाधान नहीं करता है, क्योंकि एक वेक्टर एक resizable कंटेनर है, जबकि वीएलएएस निश्चित आकार हैं। सी ++ गतिशील सरणी प्रस्ताव आधारित VLA एक भाषा के लिए विकल्प के रूप में एक पुस्तकालय आधारित समाधान पेश करने, करना है। हालाँकि, यह C ++ 0x का हिस्सा नहीं है, जहाँ तक मुझे पता है।


22
+1 और स्वीकार किया गया। एक टिप्पणी हालांकि, मुझे लगता है कि सुरक्षा तर्क थोड़ा कमजोर है, क्योंकि ढेर सारे अन्य तरीके हैं जिससे स्टफ ओवरफ्लो हो सकता है। सुरक्षा तर्क का उपयोग उस स्थिति का समर्थन करने के लिए किया जा सकता है जिसे आपको कभी भी पुनरावृत्ति का उपयोग नहीं करना चाहिए और आपको ढेर से सभी वस्तुओं को आवंटित करना चाहिए ।
एंड्रियास ब्रिंक

17
तो आप कह रहे हैं कि क्योंकि वहाँ ढेर overflows कारण के लिए अन्य तरीके हैं, हम भी उनमें से अधिक प्रोत्साहित कर सकते हैं?
जलफ ११’०

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

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

1
@ हेल्प्स: शायद उसके लिए सबसे अच्छा क्या होगा जो एक प्रकार का होगा जो कुछ हद तक व्यवहार करता है vectorलेकिन इसके लिए एक निश्चित LIFO उपयोग पैटर्न की आवश्यकता होती है और एक या एक से अधिक प्रति-सूत्रबद्ध रूप से आवंटित बफ़र्स को बनाए रखता है जो आमतौर पर सबसे बड़े कुल आवंटन के अनुसार आकार के होते हैं। कभी इस्तेमाल किया, लेकिन जो स्पष्ट रूप से छंटनी की जा सकती है। एक सामान्य "आवंटन" सामान्य मामले में एक पॉइंटर कॉपी, पॉइंटर-से-पॉइंटर घटाव, पूर्णांक तुलना और पॉइंटर जोड़ के अलावा और कुछ भी नहीं चाहिए; डी-आवंटन के लिए बस एक पॉइंटर कॉपी की आवश्यकता होगी। वीएलए की तुलना में बहुत धीमा नहीं है।
सुपरकैट

216

(पृष्ठभूमि: मुझे C और C ++ कंपाइलर को लागू करने का कुछ अनुभव है।)

C99 में चर-लंबाई सरणियाँ मूल रूप से एक गलत कदम था। वीएलए का समर्थन करने के लिए, C99 को सामान्य ज्ञान के लिए निम्नलिखित रियायतें देनी थीं:

  • sizeof xअब हमेशा एक संकलन-समय स्थिर नहीं रहता है; संकलक को कभी-कभी sizeofरन-टाइम पर एक- डेक्प्रेशन का मूल्यांकन करने के लिए कोड उत्पन्न करना चाहिए ।

  • द्वि-आयामी VLAs ( int A[x][y]) की अनुमति देते हुए 2 डी VLAs पैरामीटर के रूप में कार्य करने वाले कार्यों की घोषणा के लिए एक नए सिंटैक्स की आवश्यकता है void foo(int n, int A[][*]):।

  • C ++ दुनिया में कम महत्वपूर्ण है, लेकिन एम्बेडेड सिस्टम सिस्टम प्रोग्रामर के C लक्षित दर्शकों के लिए अत्यंत महत्वपूर्ण है, VLA घोषित करने का मतलब है कि आपके स्टैक का एक मनमाने ढंग से बड़ा हिस्सा काटना। यह एक गारंटीकृत स्टैक-ओवरफ्लो और क्रैश है। (जब भी आप घोषणा करते हैं int A[n], आप स्पष्ट रूप से दावा कर रहे हैं कि आपके पास 2 जीबी स्टैक है स्पेयर करने के लिए। आखिरकार, यदि आप जानते हैं कि " nनिश्चित रूप से यहां 1000 से कम है", तो आप बस घोषित करेंगे int A[1000]। 32-बिट पूर्णांक के nलिए प्रतिस्थापन 1000एक प्रवेश है। आपको पता नहीं है कि आपके कार्यक्रम का व्यवहार क्या होना चाहिए। "

ठीक है, तो चलिए अब C ++ के बारे में बात करते हैं। C ++ में, हमारे पास "टाइप सिस्टम" और "वैल्यू सिस्टम" के बीच समान मजबूत अंतर है जो C89 करता है ... लेकिन हमने वास्तव में उन तरीकों पर भरोसा करना शुरू कर दिया है जो C ने नहीं किए हैं। उदाहरण के लिए:

template<typename T> struct S { ... };
int A[n];
S<decltype(A)> s;  // equivalently, S<int[n]> s;

यदि nएक संकलन-समय स्थिर नहीं था (यानी, यदि Aवैरिएबल संशोधित प्रकार के थे), तो पृथ्वी पर क्या प्रकार होगा S? चाहेंगे Sके प्रकार भी केवल रनटाइम पर निर्धारित किया?

इस बारे में क्या:

template<typename T> bool myfunc(T& t1, T& t2) { ... };
int A1[n1], A2[n2];
myfunc(A1, A2);

संकलक को कुछ तात्कालिकता के लिए कोड उत्पन्न करना चाहिए myfunc। उस कोड को कैसा दिखना चाहिए? यदि हम A1संकलित समय के प्रकार को नहीं जानते हैं, तो हम वैधानिक रूप से उस कोड को कैसे उत्पन्न कर सकते हैं ?

इससे भी बदतर, क्या होगा अगर यह रनटाइम पर निकलता है n1 != n2, ताकि !std::is_same<decltype(A1), decltype(A2)>()? उस स्थिति में, कॉल को myfunc संकलित नहीं किया जाना चाहिए , क्योंकि टेम्पलेट प्रकार की कटौती विफल होनी चाहिए! हम संभवतः उस व्यवहार को रनटाइम में कैसे अनुकरण कर सकते हैं?

मूल रूप से, C ++ अधिक -से- अधिक निर्णयों को संकलन-समय में धकेलने की दिशा में आगे बढ़ रहा है : टेम्प्लेट कोड पीढ़ी, constexprफ़ंक्शन मूल्यांकन, और इसी तरह। इस बीच, C99 पारंपरिक रूप से आगे बढ़ाने में व्यस्त था संकलन समय निर्णय (जैसे sizeof) में क्रम । इसे ध्यान में रखते, यह वास्तव में भी भावना किसी भी प्रयास में खर्च करने पड़ता है की कोशिश कर रहा सी में C99 शैली Vlas एकीकृत करने के लिए ++?

के रूप में हर दूसरे उत्तर देने पहले ही बताया गया है, सी ++ ढेर-आवंटन तंत्र के बहुत सारे प्रदान करता है ( std::unique_ptr<int[]> A = new int[n];या std::vector<int> A(n);स्पष्ट लोगों जा रहा है) जब तुम सच में विचार व्यक्त करना चाहता "मैं पता नहीं कितनी RAM मैं आवश्यकता हो सकती है है।" और C ++ अपरिहार्य स्थिति से निपटने के लिए एक निफ्टी अपवाद-हैंडलिंग मॉडल प्रदान करता है कि आपके द्वारा आवश्यक RAM की मात्रा आपके पास RAM की मात्रा से अधिक है। लेकिन उम्मीद है कि यह उत्तर आपको एक अच्छा विचार देता है कि C99 शैली के वीएलएए सी + + के लिए एक अच्छा फिट क्यों नहीं थे - और वास्तव में सी 99 के लिए एक अच्छा फिट भी नहीं है। ;)


इस विषय पर अधिक जानकारी के लिए, N3810 "ऐरे एक्सटेंशन के लिए विकल्प" , ब्रेज़न स्ट्रॉस्ट्रुप का वीवीएएस पर अक्टूबर 2013 का पेपर देखें। बज़्ने की पीओवी खदान से बहुत अलग है; N3810 चीजों के लिए एक अच्छा C ++ ish सिंटैक्स खोजने पर अधिक ध्यान केंद्रित करता है, और C ++ में कच्चे सरणियों के उपयोग को हतोत्साहित करने पर, जबकि मैंने मेटाप्रोग्रामिंग और टाइपिस्ट के लिए निहितार्थ पर अधिक ध्यान केंद्रित किया है। मुझे नहीं पता कि क्या वह मेटाप्रोग्रामिंग / टाइपसिस्टम निहितार्थ को हल करता है, सॉल्व करता है, या केवल निर्बाध मानता है।


एक अच्छा ब्लॉग पोस्ट जो इन समान बिंदुओं में से कई को हिट करता है, "वैरिएबल यूज ऑफ वेरिएबल लेंथ एरेस " (क्रिस वेल्स, 2019-10-27)।


15
मैं मानता हूं कि वीएलए सिर्फ गलत थे। बहुत अधिक व्यापक रूप से लागू किया गया है, और कहीं अधिक उपयोगी है, alloca()इसके बजाय C99 में मानकीकृत किया जाना चाहिए था। वीएलएएस तब होता है जब एक मानक समिति कार्यान्वयन के आगे कूद जाती है, इसके बजाय अन्य तरीके से।
मैडिसिनिस्ट

10
चर-संशोधित प्रकार की प्रणाली एक महान आईएमओ है, और आपकी कोई भी बुलेट बिंदु सामान्य ज्ञान का उल्लंघन नहीं करता है। (1) सी मानक "संकलन-समय" और "रन-टाइम" के बीच अंतर नहीं करता है, इसलिए यह एक गैर-मुद्दा है; (2) *वैकल्पिक है, आप लिख सकते हैं (और चाहिए) int A[][n]; (3) आप वास्तव में किसी भी वीएलए को घोषित किए बिना प्रकार प्रणाली का उपयोग कर सकते हैं। उदाहरण के लिए कोई फ़ंक्शन विभिन्न प्रकार के सरणी को स्वीकार कर सकता है, और इसे विभिन्न आयामों के गैर-वीएलए 2-डी सरणियों के साथ कहा जा सकता है। हालाँकि आप अपनी पोस्ट के उत्तरार्द्ध में मान्य बिंदु बनाते हैं।
MM

3
"वीएलए घोषित करने का मतलब है कि आपके स्टैक का एक मनमाने ढंग से बड़ा हिस्सा काटना। यह एक गारंटीकृत स्टैक-ओवरफ्लो और क्रैश है। (जब भी आप इंट ए [एन] की घोषणा करते हैं, तो आप स्पष्ट रूप से दावा कर रहे हैं कि आपके पास 2 जीबी स्टैक टू स्पेयर है") झूठा। मैं अभी तक बिना किसी स्टैक अतिप्रवाह के 2GB से कम स्टैक के साथ एक वीएलए प्रोग्राम चलाता था।
जेफ

3
@ जेफ़: nआपके परीक्षण के मामले में अधिकतम मूल्य क्या था, और आपके स्टैक का आकार क्या था? मेरा सुझाव है कि आप nअपने स्टैक के आकार के रूप में कम से कम बड़े के लिए मान इनपुट करने का प्रयास करें। (और अगर nआपके कार्यक्रम के मूल्य को नियंत्रित करने के लिए उपयोगकर्ता के पास कोई रास्ता नहीं है , तो मेरा सुझाव है कि आप nसीधे घोषणा में अधिकतम मूल्य का प्रचार करें : घोषणा करें int A[1000]या जो भी आपको ज़रूरत है। वीएलए केवल आवश्यक हैं, और केवल खतरनाक हैं। जब nकिसी भी छोटे संकलन-समय स्थिर से अधिकतम मूल्य नहीं होता है।)
क्क्सप्लसोन

2
चूँकि alloca () को इस तरह के आंतरिक का उपयोग करके लागू किया जा सकता है, यह सच है कि alloca () को किसी भी प्लेटफ़ॉर्म पर कंपाइलर मानक फ़ंक्शन के रूप में लागू किया जा सकता है। ऐसा कोई कारण नहीं है कि संकलक एलोका () के पहले उदाहरण का पता नहीं लगा सका और कोड में एम्बेडेड होने के लिए चिह्नों और रिलीज के प्रकारों की व्यवस्था करता है, और कोई कारण नहीं है कि एक कंपाइलर एलोका का उपयोग नहीं कर सकता () यदि यह स्टैक के साथ नहीं किया जा सकता है। हार्ड / नॉन-पोर्टेबल क्या है एक सी कंपाइलर के शीर्ष पर लागू किया गया एलाका () है , ताकि यह कंपाइलर और ऑपरेटिंग सिस्टम की एक विस्तृत सरणी में काम करता है।
मैडिसिनिस्ट

26

आप हमेशा स्टैक पर मेमोरी आवंटित करने के लिए एलोका () का उपयोग कर सकते हैं, यदि आप चाहें तो:

void foo (int n)
{
    int *values = (int *)alloca(sizeof(int) * n);
}

स्टैक पर आबंटित होने का अर्थ है कि जब स्टैक समाप्त हो जाता है तो यह स्वचालित रूप से मुक्त हो जाएगा।

त्वरित ध्यान दें: जैसा कि ऑलका (3) के लिए मैक ओएस एक्स मैन पेज में उल्लेख किया गया है, "एलोका () फ़ंक्शन मशीन और कंपाइलर निर्भर है; इसका उपयोग अप्रयुक्त है।" बस तुम इतना जानते हो।


4
साथ ही, एलोका () पूरे फंक्शन का है, न कि केवल कोड वाले ब्लॉक के वैरिएबल का। तो एक लूप के अंदर इसका उपयोग करना लगातार स्टैक को बढ़ाएगा। एक वीएलए के पास यह समस्या नहीं है।
शश्लोअम

3
हालांकि, वीएलए को एन्कोडिंग ब्लॉक का दायरा होने का मतलब है कि वे पूरे फ़ंक्शन के दायरे के साथ एलाका () की तुलना में काफी कम उपयोगी हैं। विचार करें: if (!p) { p = alloca(strlen(foo)+1); strcpy(p, foo); } यह वीएलए के साथ नहीं किया जा सकता है, ठीक उनके ब्लॉक दायरे के कारण।
मैडिसटिसिस्ट

1
यही कारण है कि ओपी के उत्तर नहीं मिलता है क्यों सवाल। इसके अलावा, यह एक समान Cसमाधान है, और वास्तव में नहीं है C++
एड्रियन डब्ल्यू

13

अपने काम में, मैंने महसूस किया है कि हर बार जब मुझे वैरिएबल-लेंथ ऑटोमैटिक एरेज़ या एलोका () जैसी कोई चीज़ चाहिए होती है, तो मुझे इस बात का बिलकुल ख्याल नहीं था कि मेमोरी शारीरिक रूप से सीपीयू स्टैक पर स्थित है, बस इससे आया था कुछ स्टैक एलोकेटर जो सामान्य हीप को धीमी यात्राएं नहीं देते थे। इसलिए मेरे पास एक प्रति-थ्रेड ऑब्जेक्ट है, जो कुछ मेमोरी का मालिक है, जिसमें से यह चर / पॉप वेरिएबल बफ़र को धक्का दे सकता है। कुछ प्लेटफार्मों पर मैं इसे एमएमयू के माध्यम से विकसित करने की अनुमति देता हूं। अन्य प्लेटफार्मों का एक निश्चित आकार होता है (आमतौर पर एक निश्चित आकार के सीपीयू स्टैक के साथ ही क्योंकि कोई एमएमयू नहीं होता है)। एक मंच (मैं एक हैंडहेल्ड गेम कंसोल) के साथ काम करता हूं, वैसे भी कीमती थोड़ा सीपीयू स्टैक है क्योंकि यह दुर्लभ, तेज मेमोरी में रहता है।

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


12

ऐसी परिस्थितियां हैं जहां प्रदर्शन किए गए कार्यों की तुलना में ढेर मेमोरी आवंटित करना बहुत महंगा है। एक उदाहरण मैट्रिक्स गणित है। यदि आप छोटे मैट्रीस के साथ काम करते हैं तो 5 से 10 तत्व कहते हैं और बहुत सारे अंकगणित करते हैं, मॉलॉक ओवरहेड वास्तव में महत्वपूर्ण होगा। एक ही समय में आकार को एक संकलन समय स्थिर बनाना बहुत ही बेकार और अनम्य लगता है।

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


12

लगता है कि यह C ++ 14 में उपलब्ध होगा:

https://en.wikipedia.org/wiki/C%2B%2B14#Runtime-sized_one_dimensional_arrays

अपडेट: इसे C ++ 14 में नहीं बनाया।


दिलचस्प। हर्ब सटर इसकी चर्चा यहां डायनामिक एरे के तहत करता है : isocpp.org/blog/2013/04/04/trip-report-iso-c-spring-2013-meeting (यह विकिपीडिया जानकारी के लिए संदर्भ है)
डिफ़ॉल्ट

1
"रन-टाइम आकार सरणियों और डायनेरे को 18 जनवरी 2014 को विकिपीडिया पर 78.86.152.103 में लिखे गए एरेले एक्सटेंशन्स टेक्निकल स्पेसिफिकेशन में ले जाया गया है: en.wikipedia.org/w/…
strager

10
विकिपीडिया एक आदर्श संदर्भ नहीं है :) इस प्रस्ताव ने इसे C ++ 14 में शामिल नहीं किया।
MM

2
@ViktorSehr: इस wr C ++ 17 की स्थिति क्या है?
ईनपोकलम

@einpoklum कोई विचार नहीं, बढ़ावा का उपयोग करें :: कंटेनर :: static_vector
विक्टर सेहर

7

इसे C ++ / 1x में शामिल करने पर विचार किया गया था, लेकिन इसे हटा दिया गया (यह एक सुधार है जो मैंने पहले कहा था)।

सी ++ में वैसे भी यह कम उपयोगी होगा क्योंकि हमें पहले ही std::vectorइस भूमिका को भरना है।


42
नहीं, हम नहीं करते हैं, एसटीडी :: वेक्टर स्टैक पर डेटा आवंटित नहीं करता है। :)
कोस

7
"स्टैक" एक कार्यान्वयन विवरण है; कंपाइलर मेमोरी को कहीं से भी आवंटित कर सकता है, जब तक कि ऑब्जेक्ट लाइफटाइम के बारे में गारंटी पूरी न हो जाए।
MM

1
@MM: पर्याप्त उचित है, लेकिन व्यवहार में हम अभी भी std::vectorइसके बजाय, कहते हैं, का उपयोग नहीं कर सकते alloca()
ईनपोकलम

@einpoklum आपके प्रोग्राम के लिए सही आउटपुट पाने के मामले में, आप कर सकते हैं। प्रदर्शन एक गुणवत्ता-कार्यान्वयन का मुद्दा है
MM

1
@MM गुणवत्ता-का-कार्यान्वयन पोर्टेबल नहीं है। और अगर आपको प्रदर्शन की आवश्यकता नहीं है, तो आप पहली जगह में c ++ का उपयोग नहीं करते हैं
PAL

3

इसके लिए std :: वेक्टर का उपयोग करें। उदाहरण के लिए:

std::vector<int> values;
values.resize(n);

मेमोरी को ढेर पर आवंटित किया जाएगा, लेकिन यह केवल एक छोटा प्रदर्शन दोष है। इसके अलावा, यह बुद्धिमान है कि स्टैक पर बड़े डेटाब्लॉक आवंटित न करें, क्योंकि यह आकार में सीमित है।


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

1
तुम बस का उपयोग क्यों नहीं करते std::vector<int> values(n);? resizeनिर्माण के बाद उपयोग करके आप गैर-जंगम प्रकारों को प्रतिबंधित कर रहे हैं।
एलएफ

1

C99 VLA की अनुमति देता है। और यह वीएलए को घोषित करने के तरीके पर कुछ प्रतिबंध लगाता है। विवरण के लिए, मानक का 6.7.5.2 देखें। सी ++ वीएलए को नापसंद करता है। लेकिन g ++ इसे अनुमति देता है।


क्या आप उस मानक अनुच्छेद का लिंक प्रदान कर सकते हैं जिसे आप इंगित कर रहे हैं?
विंसेंट

0

इस तरह के एरेज़ C99 का हिस्सा हैं, लेकिन मानक C ++ का हिस्सा नहीं हैं। जैसा कि दूसरों ने कहा है, एक वेक्टर हमेशा एक बेहतर समाधान होता है, यही वजह है कि चर आकार के सरणियाँ C ++ स्टैंडटर्ड (या प्रस्तावित C ++ 0x मानक) में नहीं हैं।

BTW, "क्यों" पर सवाल के लिए C ++ मानक तरीका है, यह मॉडरेट Usenet न्यूज़ग्रुप comp.std.c ++ है।


6
-1 वेक्टर हमेशा बेहतर नहीं होता है। अक्सर, हाँ। हमेशा, नहीं। यदि आपको केवल एक छोटे से सरणी की आवश्यकता है, तो एक ऐसे प्लेटफ़ॉर्म पर हैं जहां हीप स्पेस धीमा है, और आपकी लाइब्रेरी के वेक्टर के कार्यान्वयन में हीप स्पेस का उपयोग होता है, तो यह सुविधा बहुत अच्छी तरह से मौजूद हो सकती है।
पैट्रिक एम

-1

यदि आप संकलन समय पर मूल्य जानते हैं तो आप निम्न कार्य कर सकते हैं:

template <int X>
void foo(void)
{
   int values[X];

}

संपादित करें: आप एक वेक्टर बना सकते हैं जो स्टैक एलोकेटर (एलोका) का उपयोग करता है, क्योंकि आवंटन एक टेम्पलेट पैरामीटर है।


18
यदि आप संकलन समय पर मूल्य जानते हैं, तो आपको किसी टेम्पलेट की आवश्यकता नहीं है। बस अपने गैर-टेम्पलेट फ़ंक्शन में सीधे X का उपयोग करें।
रोब कैनेडी

3
कभी-कभी कॉल करने वाले को संकलन-समय पर पता चलता है और कैली नहीं करता है, यही टेम्प्लेट के लिए अच्छा है। बेशक, सामान्य मामले में, कोई भी एक्स को रन-टाइम तक नहीं जानता है।
क्वर्टी जू

आप एसटीएल आवंटन में एलोका का उपयोग नहीं कर सकते हैं - स्टैक फ्रेम के नष्ट होने पर एलोका से आवंटित मेमोरी को मुक्त कर दिया जाएगा - यही वह तरीका है जब स्मृति रिटर्न आवंटित करना चाहिए।
ओलिवर

-5

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

void varTest(int iSz)
{
    char *varArray;
    __asm {
        sub esp, iSz       // Create space on the stack for the variable array here
        mov varArray, esp  // save the end of it to our pointer
    }

    // Use the array called varArray here...  

    __asm {
        add esp, iSz       // Variable array is no longer accessible after this point
    } 
}

यहाँ खतरे बहुत से हैं, लेकिन मैं कुछ समझाता हूँ: 1. चर आकार को आधे रास्ते से बदलने से स्टैक की स्थिति समाप्त हो जाएगी। 2. सरणी सीमाओं को ओवरस्टेप करने से अन्य चर और संभव कोड नष्ट हो जाएंगे। 3. यह 64 बिट में काम नहीं करता है निर्माण ... उस एक के लिए अलग-अलग विधानसभा की आवश्यकता है (लेकिन एक मैक्रो उस समस्या को हल कर सकता है)। 4. कंपाइलर विशिष्ट (कंपाइलरों के बीच चलने में परेशानी हो सकती है)। मैंने कोशिश नहीं की है इसलिए मुझे नहीं पता।


... और यदि आप इसे स्वयं रोल करना चाहते हैं, तो शायद RAII वर्ग का उपयोग करें?
ईनपोकलम

आप बस बढ़ावा देने का उपयोग कर सकते हैं :: कंटेनर :: static_vector तू।
विक्टर सेहर

इसके पास अन्य संकलक के लिए समतुल्य नहीं है जिनके पास MSVC की तुलना में अधिक कच्चा असेंबली है। वीसी संभवतः समझ जाएगा कि espबदल गया है और इसके एक्सेस को ढेर करने के लिए समायोजित करेगा, लेकिन उदाहरण के लिए जीसीसी आप इसे पूरी तरह से तोड़ देंगे - कम से कम यदि आप अनुकूलन का उपयोग करते हैं और -fomit-frame-pointerविशेष रूप से।
रुस्लान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.