C ++ प्रोग्रामर को 'नया' का उपयोग कम से कम क्यों करना चाहिए?


873

मैं स्टैक ओवरफ्लो प्रश्न पर ठोकर खाई। मेमोरी स्टैड के साथ लीक :: स्ट्रिंग का उपयोग करते समय एसटीडी :: सूची <std :: string> , और टिप्पणियों में से एक यह कहता है:

newइतना उपयोग बंद करो । मैंने कोई भी कारण नहीं देखा कि आपने कहीं भी नया प्रयोग किया। आप C ++ में मूल्य के अनुसार ऑब्जेक्ट बना सकते हैं और भाषा का उपयोग करने के लिए यह बहुत बड़ा लाभ है।
आपको ढेर पर सब कुछ आवंटित करने की आवश्यकता नहीं है।
एक तरह बंद करो सोच जावा प्रोग्रामर।

मुझे वास्तव में यकीन नहीं है कि वह इसका क्या मतलब है।

क्यों वस्तुओं को C ++ में मूल्य द्वारा जितनी बार संभव हो बनाया जाना चाहिए , और आंतरिक रूप से क्या फर्क पड़ता है?
क्या मैंने उत्तर की गलत व्याख्या की?

जवाबों:


1037

दो व्यापक रूप से उपयोग की जाने वाली मेमोरी आवंटन तकनीकें हैं: स्वचालित आवंटन और गतिशील आवंटन। आमतौर पर, प्रत्येक के लिए स्मृति का एक समान क्षेत्र होता है: स्टैक और ढेर।

ढेर

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

C ++ में, इसे स्वचालित भंडारण कहा जाता है क्योंकि भंडारण का स्कोप के अंत में स्वचालित रूप से दावा किया जाता है। जैसे ही वर्तमान कोड ब्लॉक का उपयोग (सीमांकित का उपयोग करना {}) पूरा हो जाता है, उस ब्लॉक के सभी चर के लिए मेमोरी स्वचालित रूप से एकत्र हो जाती है। यह वह क्षण भी होता है जब संसाधनों को साफ करने के लिए विध्वंसक आक्रमण किए जाते हैं।

ढेर

ढेर एक और अधिक लचीला स्मृति आवंटन मोड के लिए अनुमति देता है। बहीखाता अधिक जटिल है और आवंटन धीमी है। क्योंकि वहाँ कोई अंतर्निहित रिहाई बिंदु है, तो आप स्मृति मैन्युअल जारी करना चाहिए, का उपयोग कर deleteया delete[]( freeसी में)। हालांकि, एक अंतर्निहित रिलीज बिंदु की अनुपस्थिति ढेर के लचीलेपन की कुंजी है।

गतिशील आवंटन का उपयोग करने के कारण

यहां तक ​​कि अगर ढेर का उपयोग धीमा है और संभावित रूप से मेमोरी लीक या मेमोरी विखंडन की ओर जाता है, तो गतिशील आवंटन के लिए पूरी तरह से अच्छे उपयोग के मामले हैं, क्योंकि यह कम सीमित है।

गतिशील आवंटन का उपयोग करने के दो प्रमुख कारण:

  • आप नहीं जानते कि संकलन के समय आपको कितनी मेमोरी चाहिए। उदाहरण के लिए, जब एक पाठ फ़ाइल को एक स्ट्रिंग में पढ़ा जाता है, तो आप आमतौर पर यह नहीं जानते कि फ़ाइल का आकार क्या है, इसलिए आप यह तय नहीं कर सकते कि प्रोग्राम चलाने तक कितनी मेमोरी आवंटित की जाए।

  • आप स्मृति को आवंटित करना चाहते हैं जो वर्तमान ब्लॉक को छोड़ने के बाद बनी रहेगी। उदाहरण के लिए, आप एक फ़ंक्शन लिखना चाहते string readfile(string path)हैं जो किसी फ़ाइल की सामग्री लौटाता है। इस स्थिति में, भले ही स्टैक संपूर्ण फ़ाइल सामग्री को पकड़ सकता है, आप एक फ़ंक्शन से वापस नहीं आ सकते हैं और आवंटित मेमोरी ब्लॉक को रख सकते हैं।

क्यों गतिशील आवंटन अक्सर अनावश्यक होता है

C ++ में एक विध्वंसक निर्माण होता है जिसे विध्वंसक कहते हैं । यह तंत्र आपको एक चर के जीवनकाल के साथ संसाधन के जीवनकाल को संरेखित करके संसाधनों का प्रबंधन करने की अनुमति देता है। इस तकनीक कहा जाता है आरए II और C ++ के विशिष्ठ स्थान है। यह वस्तुओं में संसाधनों को "लपेटता" है। std::stringएक आदर्श उदाहरण है। यह स्निपेट:

int main ( int argc, char* argv[] )
{
    std::string program(argv[0]);
}

वास्तव में स्मृति की एक चर राशि आवंटित करता है। std::stringवस्तु आवंटित स्मृति ढेर और उसके नाशक में यह रिलीज का उपयोग कर। इस मामले में, आपको किसी भी संसाधन को मैन्युअल रूप से प्रबंधित करने की आवश्यकता नहीं थी और फिर भी गतिशील मेमोरी आवंटन का लाभ मिला।

विशेष रूप से, इसका अर्थ है कि इस स्निपेट में:

int main ( int argc, char* argv[] )
{
    std::string * program = new std::string(argv[0]);  // Bad!
    delete program;
}

अनावश्यक डायमेंशनल मेमोरी एलोकेशन है। कार्यक्रम को अधिक टाइपिंग (!) की आवश्यकता होती है और यह मेमोरी से निपटने के लिए भूलने के जोखिम का परिचय देता है। यह कोई स्पष्ट लाभ के साथ ऐसा करता है।

आपको क्यों संभव के रूप में स्वचालित भंडारण का उपयोग करना चाहिए

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

  • तेजी से टाइप करने के लिए;
  • तेज चलने पर;
  • स्मृति / संसाधन लीक होने का खतरा कम।

बोनस अंक

संदर्भित प्रश्न में, वहाँ अतिरिक्त चिंताएं हैं। विशेष रूप से, निम्न वर्ग:

class Line {
public:
    Line();
    ~Line();
    std::string* mString;
};

Line::Line() {
    mString = new std::string("foo_bar");
}

Line::~Line() {
    delete mString;
}

वास्तव में निम्नलिखित की तुलना में उपयोग करने के लिए बहुत अधिक जोखिम भरा है:

class Line {
public:
    Line();
    std::string mString;
};

Line::Line() {
    mString = "foo_bar";
    // note: there is a cleaner way to write this.
}

कारण यह है कि std::stringएक कॉपी कंस्ट्रक्टर को ठीक से परिभाषित करता है। निम्नलिखित कार्यक्रम पर विचार करें:

int main ()
{
    Line l1;
    Line l2 = l1;
}

मूल संस्करण का उपयोग करना, इस कार्यक्रम संभावना है, दुर्घटना के रूप में यह का उपयोग करता होगा deleteदो बार एक ही स्ट्रिंग पर। संशोधित संस्करण का उपयोग करते हुए, प्रत्येक Lineउदाहरण का अपना स्ट्रिंग उदाहरण होगा , प्रत्येक की अपनी स्मृति होगी और दोनों को कार्यक्रम के अंत में जारी किया जाएगा।

अन्य नोट

ऊपर दिए गए सभी कारणों की वजह से RAII का व्यापक उपयोग C ++ में सबसे अच्छा अभ्यास माना जाता है। हालांकि, एक अतिरिक्त लाभ है जो तुरंत स्पष्ट नहीं है। असल में, यह अपने भागों के योग से बेहतर है। पूरा तंत्र रचना करता है । यह तराजू है।

यदि आप Lineक्लास को बिल्डिंग ब्लॉक के रूप में उपयोग करते हैं :

 class Table
 {
      Line borders[4];
 };

फिर

 int main ()
 {
     Table table;
 }

चार std::stringउदाहरण, चार Lineउदाहरण, एक Tableउदाहरण और सभी स्ट्रिंग सामग्री और सब कुछ स्वचालित रूप से मुक्त किया गया है


55
+1 अंत में RAII का उल्लेख करने के लिए, लेकिन अपवाद और स्टैक अनइंडिंग के बारे में कुछ होना चाहिए।
टोबू

7
@ टोबू: हाँ, लेकिन यह पोस्ट पहले से ही काफी लंबी है, और मैं इसे ओपी के सवाल पर केंद्रित रखना चाहता था। मैं अंत में एक ब्लॉग पोस्ट या कुछ और लिखूंगा और इसे यहां से लिंक करूंगा।
एंड्रे कारन

15
स्टैक आवंटन के लिए नकारात्मक का उल्लेख करने के लिए एक महान पूरक होगा (कम से कम जब तक सी ++ 1x) - आपको अक्सर सावधानी से चीजों को कॉपी करने की आवश्यकता होती है यदि आप सावधान नहीं हैं। उदाहरण के लिए जब वह मर जाता है तो एक Monsterथूक बाहर निकालता है। अपनी पद्धति में यह दुनिया के लिए खजाना जोड़ता है। यह मरने के बाद खजाने को संरक्षित करने के लिए अन्य में उपयोग करना चाहिए । विकल्प हैं (ओवरकिल हो सकते हैं), (स्वामित्व के हस्तांतरण के लिए खराब अर्थ), मूल्य (बेकार) और + (व्यापक रूप से अभी तक लागू नहीं) द्वारा पास। TreasureWorldDie()world->Add(new Treasure(/*...*/))shared_ptrauto_ptrmoveunique_ptr
kizzx2

7
आपने स्टैक-आबंटित स्थानीय चर के बारे में जो कहा है वह थोड़ा भ्रामक हो सकता है। "स्टैक" कॉल स्टैक को संदर्भित करता है, जो स्टैक फ्रेम को संग्रहीत करता है । यह ये स्टैक फ्रेम हैं जो LIFO फैशन में संग्रहीत हैं। एक विशिष्ट फ्रेम के लिए स्थानीय चर को आवंटित किया जाता है जैसे कि वे एक संरचना के सदस्य थे।
someguy

7
@someguy: वास्तव में, स्पष्टीकरण सही नहीं है। कार्यान्वयन की आवंटन नीति में स्वतंत्रता है। हालांकि, चर को एक LIFO फैशन में आरंभीकृत और नष्ट करने की आवश्यकता होती है, इसलिए सादृश्य धारण करता है। मुझे नहीं लगता कि यह जवाब को और जटिल बनाने का काम है।
आंद्रे कारन

171

क्योंकि स्टैक तेज और लीक-प्रूफ है

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


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

31
@ चार्ली सही है। स्वचालित चर तेज़ हैं और फुलप्रूफ अधिक सटीक होंगे।
ओलिवर चार्ल्सवर्थ

28
@ शार्ली: क्लास इंटर्नल्स को किसी भी तरह से स्थापित करने की आवश्यकता है। आवश्यक स्थान आवंटित करने पर तुलना की जा रही है।
ओलिवर चार्ल्सवर्थ

51
खांसी int x; return &x;
पेट्रोचन

16
तेजी से हाँ। लेकिन निश्चित रूप से मूर्ख नहीं है। कुछ भी मूर्ख नहीं है। आप एक StackOverflow :)
rxantos

107

कारण जटिल है।

सबसे पहले, C ++ कचरा एकत्र नहीं किया जाता है। इसलिए, हर नए के लिए, एक समान विलोपन होना चाहिए। यदि आप इस डिलीट को डालने में असफल रहते हैं, तो आपके पास मेमोरी लीक है। अब, इस तरह के एक साधारण मामले के लिए:

std::string *someString = new std::string(...);
//Do stuff
delete someString;

यह सरल है। लेकिन क्या होता है अगर "करो सामान" एक अपवाद फेंकता है? ओह: स्मृति रिसाव। क्या होता है अगर "सामान करो" मुद्दे returnजल्दी? ओह: स्मृति रिसाव।

और यह सबसे सरल मामले के लिए है । यदि आप उस स्ट्रिंग को किसी को वापस करने के लिए होते हैं, तो अब उन्हें इसे हटाना होगा। और अगर वे इसे एक तर्क के रूप में पारित करते हैं, तो क्या इसे प्राप्त करने वाले को इसे हटाने की आवश्यकता है? उन्हें इसे कब हटाना चाहिए?

या, आप ऐसा कर सकते हैं:

std::string someString(...);
//Do stuff

नहीं delete। ऑब्जेक्ट "स्टैक" पर बनाया गया था, और इसे एक बार दायरे से बाहर जाने पर नष्ट कर दिया जाएगा। आप ऑब्जेक्ट को वापस भी कर सकते हैं, इस प्रकार इसकी सामग्री को कॉलिंग फ़ंक्शन में स्थानांतरित कर सकते हैं। आप फ़ंक्शंस को ऑब्जेक्ट को पास कर सकते हैं (आमतौर पर संदर्भ या कॉन्स्टेंस-रेफ़रेंस के रूप में: void SomeFunc(std::string &iCanModifyThis, const std::string &iCantModifyThis)और आगे।

सभी के बिना newऔर delete। स्मृति के मालिक या इसे हटाने के लिए जिम्मेदार कौन है, इसका कोई सवाल नहीं है। यदि तुम करो:

std::string someString(...);
std::string otherString;
otherString = someString;

यह समझा जाता है कि डेटा की otherStringएक प्रति है । यह एक सूचक नहीं है; यह एक अलग वस्तु है। उनके पास समान सामग्री हो सकती है, लेकिन आप दूसरे को प्रभावित किए बिना एक को बदल सकते हैं:someString

someString += "More text.";
if(otherString == someString) { /*Will never get here */ }

विचार देखें?


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

4
@JustinTime आपको गतिशील रूप से आवंटित वस्तुओं की स्मृति को मुक्त करने के बारे में चिंता करने की आवश्यकता नहीं है जो कार्यक्रम के जीवनकाल के लिए रहने के लिए हैं। जब कोई प्रोग्राम निष्पादित होता है, तो OS इसके लिए भौतिक मेमोरी या वर्चुअल मेमोरी का एटलस बनाता है। वर्चुअल मेमोरी स्पेस के प्रत्येक पते को भौतिक मेमोरी के एक पते पर मैप किया जाता है, और जब प्रोग्राम बाहर निकलता है, तो वर्चुअल मेमोरी को मैप करने वाले सभी को मुक्त कर दिया जाता है। इसलिए, जब तक कार्यक्रम पूरी तरह से बाहर निकल जाता है, आपको आवंटित मेमोरी के बारे में चिंता करने की आवश्यकता नहीं है जो कभी भी नष्ट नहीं की जा रही है।
अइमान अल-अरियानी

75

newअंततः बनाई गई वस्तुओं को deleteलीक होना चाहिए । विध्वंसक नहीं कहा जाएगा, स्मृति को मुक्त नहीं किया जाएगा, पूरे बिट। चूंकि C ++ में कोई कचरा संग्रह नहीं है, इसलिए यह एक समस्या है।

मूल्य से निर्मित (यानी स्टैक पर) स्वचालित रूप से मर जाते हैं जब वे दायरे से बाहर जाते हैं। विध्वंसक कॉल संकलक द्वारा डाला जाता है, और मेमोरी फ़ंक्शन रिटर्न पर स्वत: मुक्त हो जाती है।

स्मार्ट पॉइंटर्स जैसे unique_ptr, shared_ptrझूलने वाली संदर्भ समस्या को हल करते हैं, लेकिन उन्हें कोडिंग अनुशासन की आवश्यकता होती है और अन्य संभावित मुद्दे (कॉपी करने की क्षमता, संदर्भ छोरों आदि) होते हैं।

इसके अलावा, भारी बहुपरत परिदृश्यों में, newधागे के बीच विवाद का एक बिंदु है; अति प्रयोग के लिए एक प्रदर्शन प्रभाव हो सकता है new। स्टैक ऑब्जेक्ट निर्माण परिभाषा थ्रेड-स्थानीय द्वारा है, क्योंकि प्रत्येक थ्रेड का अपना स्टैक है।

मान ऑब्जेक्ट का नकारात्मक पक्ष यह है कि वे एक बार होस्ट फ़ंक्शन वापस आने के बाद मर जाते हैं - आप कॉल करने वाले को वापस नहीं भेज सकते हैं, केवल कॉपी करके, वापस करके या मूल्य से आगे बढ़ सकते हैं।


9
+1। पुन: "द्वारा बनाई गई वस्तुओं newको अंततः deleteलीक होने से बचना चाहिए ।" - बदतर अभी तक, new[]द्वारा मिलान किया जाना चाहिए delete[], और यदि आप delete new[]-ed मेमोरी या delete[] new-ed मेमोरी - आप अपरिभाषित व्यवहार प्राप्त करते हैं - बहुत कम कंपाइलर इस बारे में चेतावनी देते हैं (कुछ उपकरण जैसे Cppcheck करते हैं जब वे कर सकते हैं)।
टोनी डेलारॉय

3
@TonyDelroy ऐसी परिस्थितियां हैं जहां संकलक इसे चेतावनी नहीं दे सकते। यदि कोई फ़ंक्शन पॉइंटर लौटाता है, तो इसे नया (एकल तत्व) या नया [] बनाया जा सकता है।
fbafelipe

32
  • C ++ अपने द्वारा किसी भी मेमोरी मैनेजर को नियुक्त नहीं करता है। अन्य भाषाओं जैसे C #, Java में मेमोरी को संभालने के लिए कचरा संग्रहकर्ता है
  • C ++ कार्यान्वयन आम तौर पर मेमोरी को आवंटित करने के लिए ऑपरेटिंग सिस्टम रूटीन का उपयोग करते हैं और बहुत अधिक नया / हटाएं उपलब्ध मेमोरी को टुकड़े कर सकते हैं
  • किसी भी एप्लिकेशन के साथ, यदि मेमोरी का अक्सर उपयोग किया जा रहा है, तो इसे पूर्व-आवंटित करने और जब आवश्यक न हो तब जारी करने की सलाह दी जाती है।
  • अनुचित स्मृति प्रबंधन मेमोरी लीक का नेतृत्व कर सकता है और इसे ट्रैक करना वास्तव में कठिन है। तो फ़ंक्शन के दायरे में स्टैक ऑब्जेक्ट्स का उपयोग करना एक सिद्ध तकनीक है
  • स्टैक ऑब्जेक्ट्स का उपयोग करने का नकारात्मक पक्ष यह है कि लौटने पर, कार्यों को पास करने आदि पर वस्तुओं की कई प्रतियां बनाई जाती हैं, हालांकि स्मार्ट कंपाइलर इन स्थितियों से अच्छी तरह वाकिफ हैं और उन्हें प्रदर्शन के लिए अच्छी तरह से अनुकूलित किया गया है
  • यह सी ++ में वास्तव में थकाऊ है अगर स्मृति को दो अलग-अलग स्थानों में आवंटित और जारी किया जा रहा है। रिहाई की जिम्मेदारी हमेशा एक सवाल है और ज्यादातर हम कुछ सामान्य रूप से सुलभ पॉइंटर्स, स्टैक ऑब्जेक्ट्स (अधिकतम संभव) और ऑटो_प्रेट (आरएआईआई ऑब्जेक्ट्स) जैसी तकनीकों पर भरोसा करते हैं।
  • सबसे अच्छी बात यह है कि, आपने मेमोरी पर नियंत्रण किया है और सबसे बुरी बात यह है कि यदि आप एप्लिकेशन के लिए अनुचित मेमोरी प्रबंधन को नियोजित करते हैं तो मेमोरी पर आपका कोई नियंत्रण नहीं होगा। स्मृति भ्रंशों के कारण होने वाली दुर्घटनाएं ट्रेस करने में सबसे कठिन और कठिन होती हैं।

5
दरअसल, मेमोरी को आवंटित करने वाली किसी भी भाषा में c सहित एक मेमोरी मैनेजर होता है। अधिकांश केवल बहुत सरल हैं, अर्थात int * x = malloc (4); int * y = Malloc (4); ... पहला कॉल मेमोरी आवंटित करेगा, उर्फ ​​ओएस से मेमोरी के लिए पूछें, (आमतौर पर 1k / 4k में) ताकि दूसरी कॉल, वास्तव में मेमोरी को आवंटित न करे, लेकिन आपको अंतिम चंक का एक टुकड़ा देता है जिसे इसके लिए आवंटित किया गया है। IMO, कचरा संग्रहकर्ता मेमोरी मैनेजर नहीं हैं, क्योंकि यह केवल मेमोरी के स्वत: निपटान को संभालता है। मेमोरी मैनेजर कहलाने के लिए, यह न केवल डीलक्लोकेटिंग को संभालना चाहिए, बल्कि मेमोरी को आवंटित भी करना चाहिए।
रहली

1
स्थानीय चर स्टैक का उपयोग करते हैं इसलिए malloc()आवश्यक मेमोरी आवंटित करने के लिए कंपाइलर या उसके दोस्तों को कॉल का उत्सर्जन नहीं करता है । हालांकि, स्टैक किसी भी आइटम को स्टैक के भीतर जारी नहीं कर सकता है, स्टैक मेमोरी को कभी भी जारी किया जाता है स्टैक के शीर्ष से अनइंडिंग होता है।
मिकको रैंटलैनेन

C ++ "ऑपरेटिंग सिस्टम रूटीन का उपयोग नहीं करता है"; यह भाषा का हिस्सा नहीं है, यह सिर्फ एक सामान्य कार्यान्वयन है। C ++ बिना किसी ऑपरेटिंग सिस्टम के भी चल सकता है।
ईनपोकलुम

22

मैं देखता हूं कि कुछ नए कारणों को यथासंभव करने के कुछ महत्वपूर्ण कारण छूट गए हैं:

ऑपरेटर के newपास एक गैर-नियतात्मक निष्पादन समय है

कॉलिंग newOS को आपकी प्रक्रिया के लिए एक नया भौतिक पृष्ठ आवंटित करने का कारण हो सकता है या नहीं भी कर सकता है यदि आप इसे अक्सर करते हैं तो यह काफी धीमा हो सकता है। या इसके पास पहले से ही एक उपयुक्त मेमोरी लोकेशन तैयार हो सकता है, हम नहीं जानते। यदि आपके कार्यक्रम को सुसंगत और पूर्वानुमानित निष्पादन समय की आवश्यकता है (जैसे एक वास्तविक समय प्रणाली या गेम / भौतिकी सिमुलेशन में) तो आपको newअपने समय के गंभीर छोरों से बचने की आवश्यकता है ।

ऑपरेटर newएक अंतर्निहित धागा सिंक्रनाइज़ेशन है

हां, आपने मुझे सुना है, आपके ओएस को यह सुनिश्चित करने की आवश्यकता है कि आपके पेज टेबल सुसंगत हैं और इस तरह के कॉलिंग के newकारण आपके धागे को एक अंतर्निहित मूस लॉक प्राप्त होगा। यदि आप लगातार newकई थ्रेड्स से कॉल कर रहे हैं, तो आप वास्तव में अपने थ्रेड्स को क्रमबद्ध कर रहे हैं (मैंने 32 सीपीयू के साथ ऐसा किया है, प्रत्येक पर newकुछ सौ बाइट्स प्राप्त करने के लिए हिट है , ouch! यह डीबग करने के लिए एक शाही चिता थी)

बाकी जैसे धीमा, विखंडन, त्रुटि प्रवण, आदि का उल्लेख पहले ही अन्य उत्तरों द्वारा किया जा चुका है।


2
प्लेसमेंट नए / हटाएं और हाथ से पहले मेमोरी आवंटित करने से दोनों से बचा जा सकता है। या आप स्वयं मेमोरी को आवंटित / मुक्त कर सकते हैं और फिर कंस्ट्रक्टर / डिस्ट्रक्टर को कॉल कर सकते हैं। यह तरीका है std :: वेक्टर आमतौर पर काम करता है।
rxantos

1
@rxantos कृपया ओपी पढ़ें, यह सवाल अनावश्यक मेमोरी आवंटन से बचने के बारे में है। इसके अलावा, कोई प्लेसमेंट डिलीट नहीं है।
एमिली एल।

@ ईमली यही ओपी का मतलब है, मुझे लगता है:void * someAddress = ...; delete (T*)someAddress
xryl669

1
निष्पादन समय में भी स्टैक का उपयोग नियतात्मक नहीं है। जब तक आप फोन mlock()या कुछ इसी तरह की है। ऐसा इसलिए है क्योंकि सिस्टम मेमोरी पर कम चल रहा हो सकता है और स्टैक के लिए कोई तैयार भौतिक मेमोरी पेज उपलब्ध नहीं हैं इसलिए ओएस को आगे बढ़ने से पहले डिस्क को स्वैप करने के लिए कुछ कैश (स्पष्ट गंदी मेमोरी) को स्वैप या लिखने की आवश्यकता हो सकती है।
मिकको रैंटलैनेन

1
@mikkorantalainen तकनीकी रूप से सही है, लेकिन कम स्मृति की स्थिति में सभी दांव वैसे भी प्रदर्शन से दूर हैं क्योंकि आप डिस्क पर जोर दे रहे हैं, इसलिए ऐसा कुछ भी नहीं है जो आप कर सकते हैं। यह वैसे भी नई कॉल से बचने के लिए सलाह को अमान्य नहीं करता है जब ऐसा करना उचित हो।
एमिली एल।

21

पूर्व सी ++ 17:

क्योंकि यह एक स्मार्ट पॉइंटर में परिणाम लपेटने पर भी सूक्ष्म लीक होने का खतरा है ।

"सावधान" उपयोगकर्ता पर विचार करें जो स्मार्ट पॉइंटर्स में ऑब्जेक्ट्स को लपेटने के लिए याद रखता है:

foo(shared_ptr<T1>(new T1()), shared_ptr<T2>(new T2()));

क्योंकि वहाँ इस कोड को खतरनाक है कोई गारंटी नहीं है कि या तो shared_ptrनिर्माण किया है से पहले या तो T1या T2। इसलिए, अगर में से एक new T1()या new T2()विफल रहता है अन्य सफल होता है के बाद, तो पहली वस्तु लीक हो जाएगा नहीं है क्योंकि shared_ptrनष्ट करने और यह पुनःआवंटन मौजूद है।

समाधान: उपयोग make_shared

पोस्ट-सी ++ 17:

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

बैरी द्वारा एक अन्य उत्तर में C ++ 17 द्वारा पेश किए गए नए मूल्यांकन आदेश का अधिक विस्तृत विवरण प्रदान किया गया था ।

@Remy Lebeau को इंगित करने के लिए धन्यवाद कि यह अभी भी C ++ 17 (हालाँकि इससे कम है) के तहत एक समस्या है: shared_ptrनिर्माणकर्ता अपने नियंत्रण खंड और फेंक को आवंटित करने में विफल हो सकता है, जिस स्थिति में सूचक इसे करने के लिए पारित नहीं करता है।

समाधान: उपयोग make_shared


5
अन्य समाधान: कभी भी गतिशील रूप से प्रति पंक्ति एक से अधिक ऑब्जेक्ट को आवंटित नहीं करें।
एंटीमनी

3
@Antimony: हाँ, जब आप पहले से किसी को आवंटित नहीं करते हैं, तो उसकी तुलना में एक से अधिक ऑब्जेक्ट आवंटित करने के लिए यह बहुत अधिक आकर्षक है।
user541686

1
मुझे लगता है कि एक बेहतर उत्तर यह है कि अगर कोई अपवाद कहा जाता है, तो smart_ptr लीक हो जाएगा और कुछ भी नहीं पकड़ता है।
नेटली एडम्स

2
यहां तक ​​कि पोस्ट-सी ++ 17 मामले में, एक रिसाव अभी भी हो सकता है यदि newसफल होता है और फिर बाद में shared_ptrनिर्माण विफल हो जाता है। std::make_shared()वह भी हल होता है,
रेमी Lebeau

1
@ मेहरदाद shared_ptrप्रश्न में कंस्ट्रक्टर एक नियंत्रण ब्लॉक के लिए मेमोरी आवंटित करता है जो साझा पॉइंटर और डेलेटर को स्टोर करता है, इसलिए हां, यह सैद्धांतिक रूप से मेमोरी एरर को फेंक सकता है। केवल कॉपी, चाल और निर्माणकर्ता गैर-फेंकने वाले हैं। make_sharedनियंत्रण ब्लॉक के अंदर साझा किए गए ऑब्जेक्ट को स्वयं आवंटित करता है, इसलिए 2 के बजाय केवल 1 आवंटन है
रेमी लेबेउ

17

बहुत हद तक, यह कोई अपनी कमजोरियों को एक सामान्य नियम तक बढ़ा रहा है। कुछ भी गलत है असल का उपयोग कर वस्तुओं बनाने के साथ newऑपरेटर। इसके लिए कुछ तर्क है कि आपको कुछ अनुशासन के साथ ऐसा करना है: यदि आप एक वस्तु बनाते हैं तो आपको यह सुनिश्चित करने की आवश्यकता है कि यह नष्ट होने वाला है।

स्वचालित संग्रहण में ऑब्जेक्ट बनाने का सबसे आसान तरीका है, इसलिए C ++ इसे तब नष्ट करना जानता है जब यह दायरे से बाहर हो जाता है:

 {
    File foo = File("foo.dat");

    // do things

 }

अब, निरीक्षण करें कि जब आप अंत-ब्रेस के बाद उस ब्लॉक से गिरते हैं, तो fooयह गुंजाइश से बाहर है। C ++ आपके dtor को स्वचालित रूप से आपके लिए कॉल करेगा। जावा के विपरीत, आपको इसे खोजने के लिए GC की प्रतीक्षा करने की आवश्यकता नहीं है।

आपने लिखा था?

 {
     File * foo = new File("foo.dat");

आप इसके साथ स्पष्ट रूप से मेल खाना चाहेंगे

     delete foo;
  }

या इससे भी बेहतर, अपने File *"स्मार्ट पॉइंटर" के रूप में आवंटित करें । यदि आप इस बारे में सावधान नहीं हैं कि यह लीक का कारण बन सकता है।

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

  class File {
    private:
      FileImpl * fd;
    public:
      File(String fn){ fd = new FileImpl(fn);}

तो FileImplहोगा अभी भी ढेर पर आवंटित किया।

और हाँ, आप बेहतर होना सुनिश्चित करेंगे

     ~File(){ delete fd ; }

कक्षा में भी; इसके बिना, आप ढेर से मेमोरी को लीक कर देंगे, भले ही आपने स्पष्ट रूप से ढेर पर आवंटित नहीं किया हो ।


4
आपको संदर्भित प्रश्न में कोड पर एक नज़र रखना चाहिए। उस कोड में निश्चित रूप से बहुत सी चीजें गलत हो रही हैं।
एंड्रे कैर

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

5
निष्पक्ष बिंदु। लेकिन सामान्य नुकसान से बचने के लिए सामान्य नियम लागू किए जाते हैं। यह एक व्यक्ति की कमजोरी थी या नहीं, स्मृति प्रबंधन इस तरह के एक सामान्य नियम को वारंट करने के लिए पर्याप्त जटिल है! :)
रोबेन_फोर्ड_फैन_बॉय

9
@Charlie: टिप्पणी यह नहीं कहती है कि आपको कभी भी उपयोग नहीं करना चाहिए new। यह कहता है कि यदि आपके पास गतिशील आवंटन और स्वचालित भंडारण के बीच विकल्प है, तो स्वचालित भंडारण का उपयोग करें।
एंड्रे कारन

8
@Charlie: उपयोग करने में कुछ भी गलत नहीं है new, लेकिन यदि आप उपयोग करते हैं delete, तो आप इसे गलत कर रहे हैं!
मैथ्यू एम।

16

new()के रूप में नहीं किया जाना चाहिए थोड़ा संभव के रूप में। इसका उपयोग यथासंभव सावधानी से किया जाना चाहिए । और इसका उपयोग व्यावहारिक रूप से निर्धारित के रूप में आवश्यक रूप से अक्सर किया जाना चाहिए।

स्टैक पर वस्तुओं का आवंटन, उनके निहित विनाश पर निर्भर करता है, एक सरल मॉडल है। यदि किसी ऑब्जेक्ट का आवश्यक दायरा उस मॉडल पर फिट बैठता है तो NULL पॉइंटर्स new()की संबद्धता delete()और जाँच के साथ उपयोग करने की कोई आवश्यकता नहीं है । ऐसे मामले में जहां आपके पास ढेर सारी अल्पकालिक वस्तुएं हैं, ढेर पर आवंटन को ढेर के विखंडन की समस्याओं को कम करना चाहिए।

हालाँकि, यदि आपकी वस्तु का जीवनकाल वर्तमान दायरे से बाहर जाने की आवश्यकता new()है तो सही उत्तर है। बस सुनिश्चित करें कि आप delete()डिलीट किए गए ऑब्जेक्ट्स और पॉइंटर्स के उपयोग के साथ आने वाले अन्य सभी गोचरों का उपयोग करके कॉल और कैसे और नाउल पॉइंटर्स की संभावनाओं पर ध्यान दें ।


9
"यदि आपकी वस्तु का जीवनकाल वर्तमान दायरे से आगे बढ़ने की जरूरत है तो नया () सही उत्तर है" ... क्यों न मान से वापसी करें या नॉन- constरिफ या पॉइंटर द्वारा कॉलर-स्कोप किए गए चर को स्वीकार करें ...?
टोनी डेलारॉय

2
@ टोनी: हाँ, हाँ! मुझे किसी के संदर्भ की वकालत करते हुए खुशी हुई। वे इस समस्या को रोकने के लिए बनाए गए थे।
नाथन उस्मान

@TonyD ... या उन्हें संयोजित करें: मूल्य द्वारा एक स्मार्ट पॉइंटर लौटाएं। इस तरह फोन करने वाले और कई मामलों में (यानी जहां make_shared/_uniqueप्रयोग करने योग्य है) कॉल प्राप्त करने वाला करने की जरूरत कभी नहीं newया delete। यह उत्तर वास्तविक बिंदुओं को याद करता है: (ए) सी ++ आरवीओ जैसी चीजें प्रदान करता है, शब्दार्थ और आउटपुट मापदंडों को स्थानांतरित करता है - जिसका अर्थ है कि गतिशील रूप से आवंटित स्मृति को वापस करके ऑब्जेक्ट निर्माण और आजीवन विस्तार को संभालना अनावश्यक और लापरवाह हो जाता है। (बी) उन स्थितियों में भी जहां गतिशील आवंटन की आवश्यकता होती है, स्टैडलिब RAII आवरण प्रदान करता है जो उपयोगकर्ता को बदसूरत आंतरिक विवरण से छुटकारा दिलाता है।
अंडरस्कोर_ड

14

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

Class var;

इसे स्टैक पर रखा गया है।

आपको हमेशा उस ऑब्जेक्ट पर विनाश को कॉल करना होगा जिसे आपने नए के साथ ढेर पर रखा था। यह मेमोरी लीक की संभावना को खोलता है। स्टैक पर रखी गई वस्तुओं में मेमोरी लीक होने का खतरा नहीं है!


2
+1 "[ढेर] आम तौर पर जब आप विस्तार का अनुमान लगाते हैं" - जैसे कि std::stringया std::map, हाँ, उत्सुक अंतर्दृष्टि के लिए संलग्न करना। मेरी प्रारंभिक प्रतिक्रिया "थी, लेकिन कोड बनाने की गुंजाइश से किसी वस्तु के जीवनकाल को कम करने के लिए भी बहुत सामान्य थी", लेकिन वास्तव में गैर- constसंदर्भ या पॉइंटर द्वारा कॉलर-स्कोप किए गए मानों को स्वीकार करना या वापस लेना बेहतर होता है, सिवाय इसके कि जब "विस्तार" शामिल हो; भी। हालांकि फैक्ट्री के तरीकों की तरह कुछ अन्य साउंड का उपयोग होता है ....
टोनी डेलरो

12

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

यही समस्या है कि मेमोरी पूल जहां हल करने के लिए बनाया गया है, पारंपरिक हीप कार्यान्वयन के अंतर्निहित नुकसान को कम करने की अनुमति देता है, जबकि अभी भी आपको आवश्यक के रूप में हीप का उपयोग करने की अनुमति मिलती है।

हालांकि अभी भी पूरी तरह से समस्या से बचने के लिए बेहतर है। यदि आप इसे स्टैक पर रख सकते हैं, तो ऐसा करें।


आप हमेशा एक बड़ी मात्रा में मेमोरी आवंटित कर सकते हैं और उसके बाद प्लेसमेंट नया / डिलीट कर सकते हैं यदि गति एक समस्या है।
rxantos

मेमोरी पूल विखंडन से बचने के लिए, डीललोकेशन को गति देने के लिए (हजारों वस्तुओं के लिए एक डीलक्लोलेशन) और डीलक्लॉकर को अधिक सुरक्षित बनाने के लिए हैं।
लोथर

10

मुझे लगता है कि पोस्टर के You do not have to allocate everything on theheapबजाय कहने का मतलब था stack

मूल रूप से ऑब्जेक्ट्स को स्टैक पर आवंटित किया जाता है (यदि ऑब्जेक्ट आकार की अनुमति देता है, तो निश्चित रूप से) स्टैक-आवंटन की सस्ती लागत के बजाय, ढेर-आधारित आवंटन के बजाय जो आवंटनकर्ता द्वारा कुछ काम शामिल करता है, और वर्बोसिटी जोड़ता है क्योंकि तब आपको करना पड़ता है ढेर पर आवंटित डेटा का प्रबंधन करें।


10

मैं नए "बहुत अधिक" का उपयोग करने के विचार से असहमत हूं। हालांकि सिस्टम कक्षाओं के साथ नए पोस्टर का मूल उपयोग थोड़ा हास्यास्पद है। ( int *i; i = new int[9999];वास्तव में? int i[9999];बहुत स्पष्ट है।) मुझे लगता है कि जो टिप्पणीकार बकरी को मिल रहा था।

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

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


आमतौर पर नए / डिलीट का उपयोग तब किया जाता है जब आप सरणी के आकार को हाथ करने से पहले नहीं जानते हैं। बेशक std :: वेक्टर आपके लिए नया / हटाता है। आप अभी भी उनका उपयोग करते हैं, लेकिन गर्त std :: वेक्टर। इसलिए आजकल इसका उपयोग तब किया जाता है जब आप सरणी का आकार नहीं जानते हैं और किसी कारण से std के ओवरहेड से बचना चाहते हैं: वेक्टर (जो छोटा है, लेकिन अभी भी मौजूद है)।
rxantos

When you're working with your own classes/objects... आपके पास अक्सर ऐसा करने का कोई कारण नहीं होता है! कुशल कोडर्स द्वारा कंटेनर डिजाइन के विवरण पर क्यू का एक छोटा अनुपात है। इसके विपरीत, एक निराशाजनक अनुपात हैं या सक्रिय रूप से 'प्रोग्रामिंग' 'पाठ्यक्रम' है, जहां एक शिक्षक की मांग वे निरर्थक रूप पहिया बदलने में भयंकर कार्य दिया जाता है - - इससे पहले कि वे भी है newbies के भ्रम की स्थिति है जो पता नहीं है stdlib मौजूद है के बारे में एक पहिया क्या है और यह क्यों काम करता है यह सीखा । अधिक अमूर्त आवंटन को बढ़ावा देकर, C ++ हमें C की अंतहीन 'लिंक्ड सूची के साथ सेगफॉल्ट' से बचा सकता है; कृपया, आइए इसे करते हैं
अंडरस्कोर_ड

" सिस्टम कक्षाओं के साथ नए पोस्टर का मूल पोस्टर थोड़ा हास्यास्पद है।"int *i; i = new int[9999]; ? वास्तव में? int i[9999];बहुत स्पष्ट है।)" हाँ, यह स्पष्ट है, लेकिन शैतान के वकील की भूमिका निभाने के लिए, प्रकार आवश्यक रूप से एक बुरा तर्क नहीं है। 9999 तत्वों के साथ, मैं एक तंग एम्बेडेड सिस्टम की कल्पना कर सकता हूं जिसमें 9999 तत्वों के लिए पर्याप्त स्टैक नहीं है: 9999x4 बाइट्स ~ 40 kB, x8 ~ 80 kB है। इसलिए, ऐसी प्रणालियों को गतिशील आवंटन का उपयोग करने की आवश्यकता हो सकती है, यह मानते हुए कि वे वैकल्पिक मेमोरी का उपयोग करके इसे लागू करते हैं। फिर भी, यह केवल गतिशील आवंटन को सही ठहरा सकता है, नहीं new; एक vectorऐसी स्थिति में वास्तविक सुधार को होगा
underscore_d

@Underscore_d से सहमत - यह इतना अच्छा उदाहरण नहीं है। मैं अपने स्टैक की तरह 40,000 या 80,000 बाइट्स नहीं जोड़ूंगा। मैं वास्तव में संभवतः उन्हें ढेर पर ( std::make_unique<int[]>()निश्चित रूप से) आवंटित करूंगा ।
इइनपोकलम

3

दो कारण:

  1. यह इस मामले में अनावश्यक है। आप अपने कोड को अनावश्यक रूप से अधिक जटिल बना रहे हैं।
  2. यह ढेर पर जगह आवंटित करता है, और इसका मतलब है कि आपको deleteइसे बाद में याद रखना होगा, या यह एक मेमोरी रिसाव का कारण होगा।

2

new नया है goto

याद रखें कि gotoऐसा क्यों संशोधित किया गया है: जबकि यह प्रवाह नियंत्रण के लिए एक शक्तिशाली, निम्न-स्तरीय उपकरण है, लोग अक्सर इसे अनावश्यक रूप से जटिल तरीकों से इस्तेमाल करते थे जिससे कोड का पालन करना मुश्किल हो जाता था। इसके अलावा, सबसे उपयोगी और पढ़ने में आसान पैटर्न संरचित प्रोग्रामिंग स्टेटमेंट्स (जैसे forया while) में एन्कोडेड थे ; अंतिम प्रभाव यह है कि कोड जहां gotoउपयुक्त तरीका है, बल्कि दुर्लभ है, यदि आप लिखने के लिए ललचा रहे हैं, तो आप gotoशायद चीजों को बुरी तरह से कर रहे हैं (जब तक कि आप वास्तव में नहीं जानते कि आप क्या कर रहे हैं)।

newयह समान है - इसका उपयोग अक्सर चीजों को अनावश्यक रूप से जटिल और पढ़ने में कठिन होता है, और सबसे उपयोगी उपयोग पैटर्न को विभिन्न वर्गों में एन्कोड किया जा सकता है। इसके अलावा, यदि आपको किसी नए उपयोग पैटर्न का उपयोग करने की आवश्यकता है, जिसके लिए पहले से ही मानक कक्षाएं नहीं हैं, तो आप अपनी खुद की कक्षाएं लिख सकते हैं जो उन्हें एनकोड करती हैं!

मैं भी तर्क था कि newहै भी बदतर की तुलना में goto, इस जोड़ी की जरूरत की वजह से newऔर deleteबयान।

जैसे goto, यदि आपको कभी लगता है कि आपको उपयोग करने की आवश्यकता है new, तो आप शायद चीजों को बुरी तरह से कर रहे हैं - खासकर यदि आप एक वर्ग के कार्यान्वयन के बाहर ऐसा कर रहे हैं जिसका उद्देश्य जीवन में जो कुछ भी करने की आवश्यकता है उसे गतिशील आवंटन करना है।


और मैं जोड़ूंगा: "आपको मूल रूप से इसकी आवश्यकता नहीं है"।
einpoklum

1

मुख्य कारण यह है कि सरल मूल्यों की तुलना में ढेर पर वस्तुओं का उपयोग और प्रबंधन हमेशा मुश्किल होता है। कोड लिखना जो पढ़ना आसान है और बनाए रखना हमेशा किसी भी गंभीर प्रोग्रामर की पहली प्राथमिकता होती है।

एक अन्य परिदृश्य वह लाइब्रेरी है जिसका हम उपयोग कर रहे हैं, मूल्य शब्दार्थ प्रदान करता है और गतिशील आवंटन को अनावश्यक बनाता है। Std::stringएक अच्छा उदाहरण है।

हालाँकि ऑब्जेक्ट ओरिएंटेड कोड के लिए, एक पॉइंटर का उपयोग करते हुए - जिसका अर्थ है कि newइसे पहले से बनाने के लिए उपयोग करें - एक चाहिए। संसाधन प्रबंधन की जटिलता को सरल बनाने के लिए, हमारे पास इसे सरल बनाने के लिए दर्जनों उपकरण हैं, जैसे कि स्मार्ट पॉइंटर्स। ऑब्जेक्ट आधारित प्रतिमान या जेनेरिक प्रतिमान मान शब्दार्थ मान लेते हैं और कम या न के बराबर की आवश्यकता होती है new, जैसा कि पोस्टर में कहीं और बताया गया है।

पारंपरिक डिजाइन पैटर्न, विशेष रूप से जो गोफ पुस्तक में उल्लिखित हैं new, वे बहुत उपयोग करते हैं, क्योंकि वे विशिष्ट ओओ कोड हैं।


4
यह एक संक्षिप्त जवाब है। For object oriented code, using a pointer [...] is a must: बकवास । यदि आप केवल एक छोटे से उपसमूह, बहुरूपता का संदर्भ देकर 'OO' का अवमूल्यन कर रहे हैं - यह भी बकवास है: संदर्भ कार्य भी। [pointer] means use new to create it beforehand: विशेष रूप से बकवास : संदर्भ या संकेत स्वचालित रूप से आवंटित वस्तुओं के लिए ले जाया जा सकता है और बहुरूपिक रूप से इस्तेमाल किया जा सकता है; मुझे देखो[typical OO code] use new a lot: शायद किसी पुरानी किताब में, लेकिन किसे परवाह है? newजहाँ भी संभव हो किसी भी आधुनिक आधुनिक सी + + एचेव्स / रॉ पॉइंटर्स - और ऐसा करने से किसी भी तरह से कम ओओ नहीं है
अंडरस्कोर_ड

1

उपरोक्त सभी सही उत्तरों के लिए एक और बिंदु, यह इस बात पर निर्भर करता है कि आप किस प्रकार की प्रोग्रामिंग कर रहे हैं। उदाहरण के लिए विंडोज में विकसित कर्नेल -> स्टैक गंभीर रूप से सीमित है और आप उपयोगकर्ता मोड की तरह पृष्ठ दोष लेने में सक्षम नहीं हो सकते हैं।

ऐसे वातावरण में, नए, या सी-जैसे एपीआई कॉल पसंद किए जाते हैं और यहां तक ​​कि आवश्यक भी होते हैं।

बेशक, यह केवल नियम का एक अपवाद है।


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