C ++ में नए ऑपरेटर के साथ मेमोरी कैसे इनिशियलाइज़ करें?


176

मैं अभी C ++ में आना शुरू कर रहा हूं और मैं कुछ अच्छी आदतों को चुनना चाहता हूं। अगर मुझे ऑपरेटर के intसाथ सिर्फ एक प्रकार का आबंटन आवंटित किया गया newहै, तो मैं उन सभी को 0 से कैसे जोड़ सकता हूं, जो स्वयं उन सभी के माध्यम से लूप किए बिना हो सकता है? क्या मुझे सिर्फ उपयोग करना चाहिए memset? क्या इसे करने के लिए एक "सी ++" तरीका है?


19
यदि आप एक अच्छी सी ++ आदत चुनना चाहते हैं, तो सीधे ऐरे का उपयोग करने से बचें और इसके बजाय वेक्टर का उपयोग करें। वेक्टर सभी प्रकारों की परवाह किए बिना आरंभ करेगा, और फिर आपको डिलीट [] ऑपरेटर को कॉल करने के लिए याद रखने की आवश्यकता नहीं है।
brianegge

@brianegge: क्या होगा अगर मुझे किसी बाहरी सी फ़ंक्शन में एक सरणी पास करने की आवश्यकता है, क्या मैं इसे केवल वेक्टर दे सकता हूं?
ड्रीमलैक्स

12
आप पास कर सकते हैं &vector[0]
1

बेशक, जब आप C फ़ंक्शन में सरणियाँ पास करते हैं, तो आपको आमतौर पर पॉइंटर को पहले तत्व पर निर्दिष्ट करना होगा, और वेक्टर [0] जैसा कि @jamesdlin ने कहा है, और सरणी का आकार, इस मामले में वेक्टर.साइज़ () द्वारा प्रदान किया गया है।
ट्रेबोर रूड

संबंधित (गैर-सरणी प्रकारों के लिए पूछता है): stackoverflow.com/questions/7546620/…
Aconcagua

जवाबों:


392

यह C ++ की आश्चर्यजनक रूप से अल्प-ज्ञात विशेषता है (जैसा कि इस तथ्य से स्पष्ट होता है कि किसी ने अभी तक इसका उत्तर नहीं दिया है), लेकिन इसमें वास्तव में किसी सरणी को मान देने के लिए विशेष वाक्यविन्यास है:

new int[10]();

ध्यान दें कि आपको खाली कोष्ठक का उपयोग करना होगा - आप उदाहरण के लिए, उपयोग (0)या कुछ और नहीं कर सकते (यही कारण है कि यह केवल मूल्य आरंभीकरण के लिए उपयोगी है)।

यह स्पष्ट रूप से ISO C ++ 03 5.3.4 [expr.new] / 15 द्वारा अनुमत है, जो कहता है:

एक नई-अभिव्यक्ति जो प्रकार की एक वस्तु का निर्माण करती है, Tउस वस्तु को निम्न प्रकार से आरंभ करती है:

...

  • यदि नया-इनिशलाइज़र फॉर्म का है (), तो आइटम वैल्यू-इनिशियलाइज़्ड (8.5) है;

और इसके लिए उन प्रकारों को प्रतिबंधित नहीं करता है जिनके लिए यह अनुमति दी गई है, जबकि (expression-list)प्रपत्र को स्पष्ट रूप से उसी अनुभाग में आगे के नियमों द्वारा प्रतिबंधित किया गया है जैसे कि यह सरणी प्रकारों की अनुमति नहीं देता है।


1
हालांकि मैं मानता हूं कि यह बहुत कम ज्ञात है, मैं (पूरी तरह से) सहमत नहीं हो सकता है कि यह वास्तव में बहुत आश्चर्य की बात है - यह C ++ 03 में जोड़ा गया था, जिसे ज्यादातर लोग लगभग अनदेखा कर रहे हैं (क्योंकि यह कुछ नई चीजों में से एक था यह जोड़ा गया)।
जेरी कॉफिन

2
@ जेरी: मुझे यह स्वीकार करना चाहिए कि मुझे अभी तक पता नहीं था (शायद इसलिए कि जब मुझे मानक पढ़ना था, तो यह पहले से ही C ++ 03 था)। उस ने कहा, यह उल्लेखनीय है कि सभी कार्यान्वयन मुझे इस समर्थन का पता है (मुझे लगता है कि यह इसलिए है क्योंकि यह लागू करने के लिए बहुत तुच्छ है)।
पावेल मिनाएव

2
हाँ, यह लागू करने के लिए बहुत तुच्छ है। जहाँ तक नया है, सभी "मूल्य आरंभीकरण" C ++ 03 में नया था।
जेरी कॉफिन

34
सी ++ 11 में आप के रूप में अच्छी वर्दी initializtion उपयोग कर सकते हैं: new int[10] {}। आप इसके साथ आरंभ करने के लिए मान भी प्रदान कर सकते हैं:new int[10] {1,2,3}
bames53

कृपया वैल्यू-इनिशियलाइज़्ड के साथ डिफॉल्ट-इनिशियलाइज़ को भ्रमित न करें: वे दोनों स्पष्ट रूप से मानक में परिभाषित हैं और अलग-अलग इनिशियलाइज़ेशन हैं।
डेडुप्लिकेटर

25

यह मानते हुए कि आप वास्तव में एक सरणी चाहते हैं और एक std नहीं :: वेक्टर, "C ++ तरीका" यह होगा

#include <algorithm> 

int* array = new int[n]; // Assuming "n" is a pre-existing variable

std::fill_n(array, n, 0); 

लेकिन ध्यान रखें कि हुड के तहत यह वास्तव में अभी भी एक लूप है जो प्रत्येक तत्व को 0 पर असाइन करता है (हार्डवेयर-स्तर समर्थन के साथ एक विशेष वास्तुकला को छोड़कर, इसे करने के लिए वास्तव में एक और तरीका नहीं है)।


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

4
आप हैरान हो सकते हैं। मैं था। मेरे एसटीएल (GCC और Dinkumware दोनों) पर, std :: copy वास्तव में एक यादगार में बदल जाता है यदि यह पता लगाता है कि इसे बिल्ट इन टाइप्स के साथ कहा जा रहा है। मुझे आश्चर्य नहीं होगा अगर std :: fill_n ने मेमसेट का उपयोग किया।
ब्रायन नील

2
नहीं। प्रयोग करें 'मूल्य-प्रारंभ' 0 पर सभी सदस्यों सेट करने के लिए
मार्टिन यॉर्क में

24

आंतरिक प्रकार की एक सरणी को आवंटित करने के लिए तरीकों की संख्या है और ये सभी तरीके सही हैं, हालांकि जिसे चुनना है, निर्भर करता है ...

लूप में सभी तत्वों का मैनुअल प्रारंभिककरण

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

std::memsetसे फ़ंक्शन का उपयोग करना<cstring>

int* p = new int[10];
std::memset(p, 0, sizeof(int) * 10);

std::fill_nसे एल्गोरिथ्म का उपयोग करना<algorithm>

int* p = new int[10];
std::fill_n(p, 10, 0);

std::vectorकंटेनर का उपयोग करना

std::vector<int> v(10); // elements zero'ed

यदि C ++ 0x उपलब्ध है, तो शुरुआती सूची सुविधाओं का उपयोग करना

int a[] = { 1, 2, 3 }; // 3-element static size array
vector<int> v = { 1, 2, 3 }; // 3-element array but vector is resizeable in runtime

1
वेक्टर होना चाहिए <int> यदि आपने p = नया int जोड़ा [10] () तो आपके पास पूरी सूची थी।
कर्स्टन

@mloskot, पहले मामले में जहां आपने "नया" का उपयोग करके एक सरणी शुरू की है, संदर्भ से कैसे गुजरेंगे? यदि मैंने int array[SIZE] ={1,2,3,4,5,6,7};नोटेशन का उपयोग किया है, तो मैं उपयोग void rotateArray(int (& input)[SIZE], unsigned int k);कर सकता हूं मेरी फ़ंक्शन घोषणा होगी, पहले सम्मेलन का उपयोग करते समय क्या होगा? कोई उपाय?
अनु ०

1
मुझे डर है कि उदाहरण std::memsetगलत है - आप 10 पास करते हैं, यह बाइट्स की संख्या की उम्मीद करता है - en.cppreference.com/w/cpp/string/byte/memset देखें । (मुझे लगता है कि यह अच्छी तरह से पता चलता है कि किसी को संभव होने पर इस तरह के निम्न-स्तरीय निर्माण से क्यों बचना चाहिए।)
सुमा

@ सुमा ग्रेट कैच! फिक्स्ड। यह एक दशक पुराने बग के लिए एक उम्मीदवार प्रतीत होता है :-) हां, मैं आपकी टिप्पणी से सहमत हूं।
mloskot

7

यदि आप जो मेमोरी आवंटित कर रहे हैं, वह एक निर्माणकर्ता के साथ एक वर्ग है जो कुछ उपयोगी करता है, तो ऑपरेटर नया उस कंस्ट्रक्टर को कॉल करेगा और आपके कंप्यूटर को प्रारंभिक रूप से छोड़ देगा।

लेकिन अगर आप POD आवंटित कर रहे हैं या ऐसी कोई चीज़ जिसमें एक कंस्ट्रक्टर नहीं है जो ऑब्जेक्ट की स्थिति को इनिशियलाइज़ करता है, तो आप मेमोरी को आवंटित नहीं कर सकते हैं और एक ऑपरेशन में ऑपरेटर नई के साथ उस मेमोरी को इनिशियलाइज़ कर सकते हैं। हालाँकि, आपके पास कई विकल्प हैं:

1) इसके बजाय एक स्टैक चर का उपयोग करें। आप इस तरह एक कदम में आवंटित और डिफ़ॉल्ट शुरू कर सकते हैं :

int vals[100] = {0};  // first element is a matter of style

2) का उपयोग करें memset()। ध्यान दें कि यदि आप जिस वस्तु को आवंटित कर रहे हैं वह POD नहीं है , तो उसे रद्द करना एक बुरा विचार है। एक विशिष्ट उदाहरण यह है कि यदि आप एक ऐसे वर्ग को याद करते हैं जिसमें आभासी कार्य हैं, तो आप व्यवहार्य को उड़ा देंगे और अपनी वस्तु को अनुपयोगी अवस्था में छोड़ देंगे।

3) कई ऑपरेटिंग सिस्टम में कॉल होते हैं जो आप चाहते हैं - एक ढेर पर आवंटित करें और डेटा को किसी चीज़ से आरंभ करें। एक विंडोज उदाहरण होगाVirtualAlloc()

4) यह आमतौर पर सबसे अच्छा विकल्प है। स्मृति को स्वयं प्रबंधित करने से बचें। आप कच्चे मेमोरी के साथ कुछ भी करने के लिए एसटीएल कंटेनरों का उपयोग कर सकते हैं, जिसमें सभी को गिराने और एक ही झटके में आवंटन करने सहित शामिल हैं:

std::vector<int> myInts(100, 0);  // creates a vector of 100 ints, all set to zero

6

हाँ वहाँ है:

std::vector<int> vec(SIZE, 0);

डायनामिक रूप से आवंटित सरणी के बजाय वेक्टर का उपयोग करें। लाभ में सरणी को हटाने के साथ परेशान नहीं करना है (यह वेक्टर के दायरे से बाहर हो जाने पर हटा दिया जाता है) और यह भी कि यदि कोई अपवाद फेंका गया हो तो भी मेमोरी अपने आप डिलीट हो जाती है।

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

अब C ++ 11 के साथ, इसमें std :: array भी है जो मॉडल को एक स्थिर आकार सरणी (बनाम वेक्टर जो बढ़ने में सक्षम है)। वहाँ भी है std :: unique_ptr जो एक गतिशील रूप से आवंटित सरणी का प्रबंधन करता है (जो कि इस प्रश्न के अन्य उत्तरों में वर्णित के रूप में आरंभीकरण के साथ जोड़ा जा सकता है)। उनमें से कोई भी मैन्युअल रूप से सरणी, IMHO को सूचक को संभालने की तुलना में अधिक C ++ तरीका है।


11
यह वास्तव में पूछे गए प्रश्न का उत्तर नहीं देता है।
जॉन नोएलर

1
क्या मुझे हमेशा std::vectorगतिशील रूप से आवंटित सरणियों के बजाय उपयोग करना चाहिए ? एक वेक्टर पर एक सरणी का उपयोग करने के क्या लाभ हैं, और इसके विपरीत?
ड्रीमलैक्स

1
@ जॉन नोलर: ओपी ने इसे करने के लिए C ++ के तरीके के बारे में पूछा, मैं कहूंगा कि वेक्टर ऐसा करने का c ++ तरीका है। बेशक, आप सही हैं कि ऐसी परिस्थितियां हो सकती हैं जो अभी भी एक सादे सरणी के लिए कहेंगी और ओपी की स्थिति को नहीं जानते हुए यह एक हो सकती है। मुझे कोई अनुमान नहीं है, क्योंकि यह प्रशंसनीय है कि ओपी वैक्टर के बारे में नहीं जानता है।
विलेनथेस्पैम

1
@villintehaspam: यद्यपि यह समाधान मेरे प्रश्न का उत्तर नहीं देता है लेकिन यह वह रास्ता है जो मैं लेने जा रहा हूं। टायलर मैकहेनरी मेरे प्रश्न का अधिक सीधे उत्तर देते हैं, और विशेष रूप से उन लोगों के लिए मदद करनी चाहिए जो कुछ भी कारण - उपयोग नहीं कर सकते std::vector
ड्रीमलैक्स

2
@villintehaspam: नहीं, यह एक C ++ तरीका नहीं है। यह करने के लिए जावा तरीका है। vectorसंदर्भ की परवाह किए बिना हर जगह चिपके रहने को "C ++ में जावा कोड लिखना" कहा जाता है।
चींटी

2

std::fillएक तरीका है। क्षेत्र को भरने के लिए दो पुनरावृत्तियों और एक मान लेता है। वह, या लूप के लिए, (मुझे लगता है) अधिक C ++ तरीका होगा।

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

मेरे हिस्से के लिए, मैं हमेशा एक लूप का उपयोग करता हूं।

(मुझे लोगों के इरादों का दूसरा अनुमान लगाना पसंद नहीं है, लेकिन यह सच है कि std::vectorसभी चीजें समान हैं, उपयोग करने के लिए बेहतर हैं new[]।)


1

आप हमेशा मेमसेट का उपयोग कर सकते हैं:

int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));

मैं समझता हूं कि मैं उपयोग कर सकता हूं memset, लेकिन मुझे यकीन नहीं था कि यह समस्या का दृष्टिकोण करने के लिए C ++ तरीका था।
ड्रीमलैक्स

1
यह वास्तव में 'C ++ रास्ता' नहीं है, लेकिन फिर भी कच्चे सरणियाँ नहीं हैं।
पीट किरकम

1
@gbrandt: जो यह कहना है कि यह C या C ++ में बहुत अच्छा काम नहीं करता है। यह प्रकार के अधिकांश मूल्यों के लिए काम करता है चार या अहस्ताक्षरित चार है। यह अधिकांश प्रकारों के लिए काम करता है 0 (कम से कम अधिकांश कार्यान्वयन में)। अन्यथा, यह आम तौर पर बेकार है।
जेरी कॉफिन

1
10 * sizeof( *myArray )से अधिक प्रलेखित और परिवर्तन-प्रमाण है 10 * sizeof( int )
केविन रीड

1
किसी भी मामले में, ओपी के पास एक कच्चा सरणी है और उस सरणी को शून्य करने के लिए सबसे तेज़ और सबसे आसान तरीका है।
ग्रेगर ब्रांट

-1

आमतौर पर वस्तुओं की गतिशील सूचियों के लिए, आप एक का उपयोग करते हैं std::vector

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

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