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




सी++ प्रोग्राम्स (14)

new नया goto

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

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

मैं यह भी तर्क दूंगा कि new जोड़ी और बयान delete की आवश्यकता के कारण goto से new बुरा है।

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

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

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

मुझे सच में यकीन नहीं है कि उसका क्या मतलब है। ऑब्जेक्ट को सी ++ में जितनी बार संभव हो सके मूल्य से बनाया जाना चाहिए, और यह आंतरिक रूप से क्या अंतर करता है? क्या मैंने जवाब गलत व्याख्या किया?


क्योंकि यह सूक्ष्म रिसाव के लिए प्रवण होता है भले ही आप परिणाम को एक स्मार्ट सूचक में लपेटें

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

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

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

SolutIon: make_shared का उपयोग make_shared


दो कारण:

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

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

Class var;

यह ढेर पर रखा गया है।

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


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

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

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


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

ढेर

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

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

ढेर

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

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

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

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

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

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

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

सी ++ में एक विनाशक नामक एक साफ रचना है। यह तंत्र आपको एक चर के जीवनकाल के साथ संसाधन के जीवनकाल को संरेखित करके संसाधनों का प्रबंधन करने की अनुमति देता है। इस तकनीक को RAII कहा जाता है और सी ++ का विशिष्ट बिंदु है। यह वस्तुओं में वस्तुओं को "लपेटता है"। 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 का व्यापक उपयोग सी ++ में सबसे अच्छा अभ्यास माना जाता है। हालांकि, एक अतिरिक्त लाभ है जो तुरंत स्पष्ट नहीं है। असल में, यह इसके हिस्सों के योग से बेहतर है। पूरी तंत्र composes । यह तराजू

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

 class Table
 {
      Line borders[4];
 };

फिर

 int main ()
 {
     Table table;
 }

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


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

ऐसा करने का सबसे आसान तरीका ऑब्जेक्ट को स्वचालित स्टोरेज में बनाना है, इसलिए सी ++ स्कॉप से ​​बाहर होने पर इसे नष्ट करना जानता है:

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

    // do things

 }

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

क्या आपने लिखा था

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

आप इसे स्पष्ट रूप से मिलान करना चाहते हैं

     delete foo;
  }

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

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

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

फिर FileImpl अभी भी ढेर पर आवंटित किया जाएगा।

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

     ~File(){ delete fd ; }

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


यह जटिल है।

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

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 में कुछ otherString के डेटा की एक प्रति है। यह एक सूचक नहीं है; यह एक अलग वस्तु है। उनके पास एक ही सामग्री हो सकती है, लेकिन आप दूसरे को प्रभावित किए बिना एक को बदल सकते हैं:

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

विचार देखें?


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

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

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

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

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


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

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


मैं देखता हूं कि जितना संभव हो उतना नया करने के कुछ महत्वपूर्ण कारण मिस्ड हैं:

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

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

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

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

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


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

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

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

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


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

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

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





c++-faq