9

मान लीजिए मैं:सी ++: क्या मुझे पॉइंटर सदस्यों को प्रारंभ करना चाहिए जिन्हें कन्स्ट्रक्टर बॉडी में न्यूल में असाइन किया गया हो?

// MyClass.h 
class MyClass 
{ 
    public: 
    MyClass(); 

    private: 
    Something *something_; 
} 

// MyClass.cpp 
MyClass::MyClass() 
{ 
    something_ = new Something(); 
} 

मैं MyClass निर्माता के निर्माता प्रारंभ सूची में नल (या 0) को something_ प्रारंभ करना चाहिए? या यह जरूरी नहीं है क्योंकि मैं इसे कन्स्ट्रक्टर के शरीर में सौंप रहा हूं? अनुशंसित अभ्यास क्या है?

+8

क्यों न सिर्फ पहली जगह में सूचक प्रारंभ की बचत होती है? 'MyClass :: MyClass(): something_ (नया कुछ())' –

+0

ओह, क्या यह सबसे अच्छा अभ्यास है? – User

+3

कन्स्ट्रक्टर बॉडी में असाइनमेंट के लिए हमेशा प्रारंभ करना पसंद करते हैं। और देशी पॉइंटर के बजाय 'shared_ptr' या' scoped_ptr' जैसे स्मार्ट पॉइंटर का उपयोग करें ताकि अपवाद के मामले में क्लीनअप स्वचालित हो। –

उत्तर

11

आम तौर पर आप केवल एक बार, निर्दिष्ट, आरंभीकरण सूची या शरीर में जब तक शरीर प्रारंभ या ऐसा नहीं हो सकता है, या शर्त कोड है:

MyClass::MyClass() 
{ 
    //this code must happen first 
    // _now_ max is known 
    something_ = new Something(max); 
} 

MyClass::MyClass() 
{ 
    if (max) 
     something_ = new Something(max); 
    else 
     something_ = NULL; 
} 

MyClass::MyClass() 
    : something_(new Something()) 
//as pointed out in the comments, use smart pointers 
{ 
} 
+5

प्रारंभिक सूची_इन में गतिशील आवंटन के परिणामस्वरूप एक सूचक डेटा सदस्य प्रारंभ करना एक बुरा विचार है। बहुत सी चीजें गलत हो सकती हैं। उदाहरण के लिए, यदि किसी अन्य डेटा सदस्य के निर्माण के दौरान कोई अपवाद फेंक दिया जाता है, तो आप कैसे जानते हैं कि कौन से डेटा सदस्यों को प्रारंभ किया गया था ताकि आप गतिशील आवंटित ऑब्जेक्ट को नष्ट कर सकें? यहां तक ​​कि यदि आप फ़ंक्शन-प्रयास ब्लॉक का उपयोग करते हैं, तो आप नहीं जानते कि निर्माण कहां विफल हुआ। (बेशक, किसी को एक स्मार्ट सूचक का उपयोग करना चाहिए, जिस स्थिति में प्रारंभिक सूची में गतिशील आवंटन ठीक है, लेकिन सामान्य पॉइंटर्स का उपयोग करते समय सावधान रहें)। –

+1

@ जेम्स: ठीक है, निश्चित रूप से किसी को मूल सूचक के बजाय स्मार्ट पॉइंटर का उपयोग करना चाहिए। (हां, आपने अभी यह कहने के लिए अपनी टिप्पणी संपादित की है।) –

+0

क्या होगा यदि मैं विभिन्न वस्तुओं को बना रहा हूं और पहले को दूसरे को तर्क के रूप में आवश्यकता है? क्या आप इस मामले में प्रारंभकर्ता का उपयोग कर सकते हैं या यह आपके अधिकतम उदाहरण के समान है? (उदा। ': कुछ_ (नया कुछ()), somethingElse_ (नया SomethingElse (कुछ _)) ...') – User

2

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

+0

मैंने संभावित अपवाद सुरक्षा समस्या के बारे में नहीं सोचा था। –

1

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

  • न्यूनतम प्रदर्शन भूमि के ऊपर
  • पागल बग शिकार के साथ इतना कुछ डिबगिंग/समस्या निवारण समय
+0

* 'पागल बग शिकार' * - निश्चित रूप से। मैं अभी संसाधन संसाधन रिसाव (एक विंडोज उपयोगकर्ता ऑब्जेक्ट) के लिए शिकार कर रहा हूं, और सबसे अधिक परेशानी प्रारंभकर्ता सूची में 'नई' कॉल करती है: प्रारंभकर्ता सूचियों की "परमाणु" दुनिया में पहले/बाद में नहीं है। – Wolf

संबंधित मुद्दे