मुझे सदस्य आरंभिक सूची का उपयोग क्यों करना चाहिए?


228

मैं अपने निर्माणकर्ताओं के साथ सदस्य आरंभीकरण सूचियों का उपयोग करने के लिए आंशिक हूं ... लेकिन मैं लंबे समय से इसके पीछे के कारणों को भूल गया हूं ...

क्या आप अपने निर्माणकर्ताओं में सदस्य आरंभीकरण सूचियों का उपयोग करते हैं? यदि हां, तो क्यों? यदि नहीं, तो क्यों नहीं?


3
यहाँ सूचीबद्ध कारण ... https://www.geeksforgeeks.org/when-do-we-use-initializer-list-in-c/
u8it

जवाबों:


278

के लिए पॉड वर्ग के सदस्यों, यह कोई फर्क नहीं पड़ता है, यह शैली का मामला है। क्लास के सदस्यों के लिए जो क्लास हैं, फिर यह एक डिफॉल्ट कंस्ट्रक्टर को अनावश्यक कॉल से बचाते हैं। विचार करें:

class A
{
public:
    A() { x = 0; }
    A(int x_) { x = x_; }
    int x;
};

class B
{
public:
    B()
    {
        a.x = 3;
    }
private:
    A a;
};

इस मामले में, के लिए कंस्ट्रक्टर Bडिफॉल्ट कंस्ट्रक्टर को कॉल करेगा A, और उसके बाद a.x3. इनिशियलाइज़ कर देगा। बेहतर तरीका यह होगा कि आप शुरुआती लिस्ट में Bकंस्ट्रक्टर को सीधे कंस्ट्रक्टर को कॉल करें A:

B()
  : a(3)
{
}

यह केवल कहेंगे Aकी A(int)निर्माता और नहीं उसके डिफ़ॉल्ट निर्माता। इस उदाहरण में, अंतर नगण्य है, लेकिन कल्पना करें कि क्या आप Aडिफ़ॉल्ट निर्माता अधिक करेंगे, जैसे कि मेमोरी या फाइल को आवंटित करना। आप अनावश्यक रूप से ऐसा नहीं करना चाहेंगे।

इसके अलावा, यदि किसी क्लास में डिफॉल्ट कंस्ट्रक्टर नहीं है, या आपके पास कोई constसदस्य वैरिएबल है, तो आपको एक इनिलाइज़र सूची का उपयोग करना होगा :

class A
{
public:
    A(int x_) { x = x_; }
    int x;
};

class B
{
public:
    B() : a(3), y(2)  // 'a' and 'y' MUST be initialized in an initializer list;
    {                 // it is an error not to do so
    }
private:
    A a;
    const int y;
};

5
एक संदर्भ के महत्वपूर्ण मामले के लिए भी आवश्यक है
डीयू

5
क्यों नहीं "" (3) का उपयोग करें; या "ए = ए (3);" B के डिफ़ॉल्ट निर्माता के शरीर में?
सेर्गी

1
क्या आप बता सकते हैं, POD से आपका क्या मतलब है?
जोनास स्टीन

2
@JonasStein POD सरल डेटा संरचनाओं (पूर्ण कक्षाओं के बजाय) से संबंधित नियमों का एक अच्छी तरह से परिभाषित सेट है। और अधिक के लिए FAQ पढ़ें: stackoverflow.com/questions/146452/what-are-pod-types-in-c
monkey0506

2
@Sergey, ए का डिफ़ॉल्ट कंस्ट्रक्टर अभी भी कहा जाएगा।
वासिलिस

44

ऊपर उल्लिखित प्रदर्शन कारणों के अलावा, यदि आपकी क्लास स्टोर ऑब्जेक्ट्स के सन्दर्भ देती है, जो कंस्ट्रक्टर पैरामीटर के रूप में पास की गई है या आपकी क्लास में कॉन्स्टेबल चर हैं, तो आपके पास इनिशियल लिस्ट का उपयोग करने के अलावा कोई विकल्प नहीं है।


7
मैं मानने वाले सदस्यों के लिए भी जाता हूं।
रिचर्ड कॉर्डन

हां, कांस्टेबल चर को संशोधित करने के लिए असाइनमेंट का उपयोग नहीं किया जा सकता है, इसलिए इसे आरंभीकृत किया जाना चाहिए।
हरेन लैक्स

23
  1. आधार वर्ग की शुरूआत

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

निर्माण के आदेश के अनुसार, बाल वर्ग से पहले आधार वर्ग का निर्माण किया जाना चाहिए। कंस्ट्रक्टर इनिशियलाइज़र सूची के बिना, यह संभव है यदि आपके बेस क्लास में डिफॉल्ट कंस्ट्रक्टर है जिसे चाइल्ड क्लास के कंस्ट्रक्टर में प्रवेश करने से ठीक पहले कहा जाएगा।

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

  1. Subobjects का प्रारंभिककरण जिसमें केवल मानकीकृत कंस्ट्रक्टर हैं

  2. दक्षता

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

  1. गैर-स्थिर स्थिरांक डेटा सदस्यों को प्रारंभ करना

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

  1. संदर्भ डेटा सदस्यों का प्रारंभिककरण

जब कंपाइलर कंस्ट्रक्टर में प्रवेश करता है तो संदर्भ डेटा सदस्यों को इंटिग्रेटेड किया जाना चाहिए क्योंकि संदर्भों को केवल घोषित नहीं किया जा सकता है और बाद में प्रारंभ किया जा सकता है। यह केवल कंस्ट्रक्टर इनिशियलाइज़र सूची के साथ संभव है।


10

प्रदर्शन के मुद्दों के आगे, एक और बहुत महत्वपूर्ण है जिसे मैं कोड स्थिरता और विस्तार कहूंगा।

यदि कोई T POD है और आप आरंभीकरण सूची को प्राथमिकता देना शुरू करते हैं, तो यदि एक बार T एक गैर-POD प्रकार में बदल जाएगा, तो आपको अनावश्यक कंस्ट्रक्टर कॉल से बचने के लिए आरंभीकरण के आसपास कुछ भी बदलने की आवश्यकता नहीं होगी क्योंकि यह पहले से ही अनुकूलित है।

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

कॉन्स्टेबल सदस्यों या संदर्भ सदस्यों के साथ ही, मान लें कि प्रारंभ में T को निम्न प्रकार से परिभाषित किया गया है:

struct T
{
    T() { a = 5; }
private:
    int a;
};

अगला, आप एक कांस्टेबल के रूप में अर्हता प्राप्त करने का निर्णय लेते हैं, यदि आप प्रारंभ से सूची का उपयोग करेंगे, तो यह एक एकल पंक्ति परिवर्तन था, लेकिन टी को ऊपर के रूप में परिभाषित किया गया है, इसे असाइनमेंट को हटाने के लिए कंस्ट्रक्टर की परिभाषा को भी खोदने की आवश्यकता है:

struct T
{
    T() : a(5) {} // 2. that requires changes here too
private:
    const int a; // 1. one line change
};

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


5

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

यदि आपके पास एक संदर्भ या एक कॉन्स्टेबल फ़ील्ड है, या यदि उपयोग की जाने वाली कक्षाओं में से कोई एक डिफ़ॉल्ट निर्माता नहीं है, तो आपको आरंभीकरण सूची का उपयोग करना होगा।


2
// Without Initializer List
class MyClass {
    Type variable;
public:
    MyClass(Type a) {  // Assume that Type is an already
                     // declared class and it has appropriate 
                     // constructors and operators
        variable = a;
    }
};

यहाँ कंपाइलर MyClass
1 का ऑब्जेक्ट बनाने के लिए निम्न चरणों का पालन करता है । टाइप के कंस्ट्रक्टर को पहले "a" के लिए कहा जाता है।
2. "टाइप" के असाइनमेंट ऑपरेटर को असाइन करने के लिए MyClass () कंस्ट्रक्टर के बॉडी के अंदर बुलाया जाता है

variable = a;
  1. और फिर अंत में "टाइप" का विनाशकर्ता "ए" के लिए कहा जाता है क्योंकि यह दायरे से बाहर जाता है।

    अब MyClass () कंस्ट्रक्टर के साथ प्रारंभिक सूची के साथ समान कोड पर विचार करें

    // With Initializer List
     class MyClass {
    Type variable;
    public:
    MyClass(Type a):variable(a) {   // Assume that Type is an already
                     // declared class and it has appropriate
                     // constructors and operators
    }
    };

    प्रारंभिक सूची के साथ, संकलक द्वारा निम्नलिखित चरणों का पालन किया जाता है:

    1. "टाइप" वर्ग के कॉपी कंस्ट्रक्टर को आरंभीकृत करने के लिए कहा जाता है: चर (ए)। इनिशियलाइज़र सूची के तर्कों का उपयोग "वैरिएबल" को सीधे कॉपी करने के लिए किया जाता है।
    2. "प्रकार" का विनाशकर्ता "ए" के लिए कहा जाता है क्योंकि यह दायरे से बाहर जाता है।

2
हालांकि यह कोड स्निपेट प्रश्न को हल कर सकता है, जिसमें कोड से एक स्पष्टीकरण भी शामिल है जो वास्तव में आपके पोस्ट की गुणवत्ता को बेहतर बनाने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, और उन लोगों को आपके कोड सुझाव के कारणों का पता नहीं चल सकता है। कृपया व्याख्यात्मक टिप्पणियों के साथ अपने कोड को भीड़ने की कोशिश न करें, इससे कोड और स्पष्टीकरण दोनों की पठनीयता कम हो जाती है! meta.stackexchange.com/q/114762/308249
davejal

2
कृपया, अपनी समझ लिखें या केवल मूल स्रोत के लिए लिंक साझा करें (यहां, geeksforgeeks.com) इसे कॉपी-पेस्ट करने के बजाय।
युवी

1

बस कुछ अतिरिक्त जानकारी जोड़ने के लिए कि सदस्य आरंभीकरण सूची में कितना अंतर हो सकता है । लेटकोड में 303 रेंज सम क्वेरी - अपरिवर्तनीय, https://leetcode.com/problems/range-sum-query-immutable/ , जहां आपको कुछ आकार के साथ एक वेक्टर को शून्य बनाने और आरंभ करने की आवश्यकता होती है। यहाँ दो अलग कार्यान्वयन और गति तुलना है।

सदस्य आरंभीकरण सूची के बिना , एसी प्राप्त करने के लिए मुझे लगभग 212 एमएस खर्च करना होगा ।

class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) {
    preSum = vector<int>(nums.size()+1, 0);
    int ps = 0;
    for (int i = 0; i < nums.size(); i++)
    {
        ps += nums[i];
        preSum[i+1] = ps;
    }
}

int sumRange(int i, int j) {
    return preSum[j+1] - preSum[i];
}
};

अब सदस्य आरंभीकरण सूची का उपयोग करते हुए , एसी प्राप्त करने का समय लगभग 108 एमएस है । इस सरल उदाहरण के साथ, यह काफी स्पष्ट है कि, सदस्य आरंभीकरण सूची अधिक कुशल है । सभी माप एलसी से चल रहे समय से है।

class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) : preSum(nums.size()+1, 0) { 
    int ps = 0;
    for (int i = 0; i < nums.size(); i++)
    {
        ps += nums[i];
        preSum[i+1] = ps;
    }
}

int sumRange(int i, int j) {
    return preSum[j+1] - preSum[i];
}
};

0

वाक्य - विन्यास:

  class Sample
  {
     public:
         int Sam_x;
         int Sam_y;

     Sample(): Sam_x(1), Sam_y(2)     /* Classname: Initialization List */
     {
           // Constructor body
     }
  };

प्रारंभिक सूची की आवश्यकता:

 class Sample
 {
     public:
         int Sam_x;
         int Sam_y;

     Sample()     */* Object and variables are created - i.e.:declaration of variables */*
     { // Constructor body starts 

         Sam_x = 1;      */* Defining a value to the variable */* 
         Sam_y = 2;

     } // Constructor body ends
  };

उपरोक्त कार्यक्रम में, जब क्लास के कंस्ट्रक्टर को निष्पादित किया जाता है, तो Sam_x और Sam_y बनाए जाते हैं। फिर कंस्ट्रक्टर बॉडी में, उन सदस्य डेटा चर को परिभाषित किया जाता है।

बक्सों का इस्तेमाल करें:

  1. एक कक्षा में कांस्टेबल और संदर्भ चर

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

  1. नमूना 1 (बेस) वर्ग के सदस्य ऑब्जेक्ट जिसमें डिफ़ॉल्ट कंस्ट्रक्टर नहीं है

     class Sample1 
     {
         int i;
         public:
         Sample1 (int temp)
         {
            i = temp;
         }
     };
    
      // Class Sample2 contains object of Sample1 
     class Sample2
     {
      Sample1  a;
      public:
      Sample2 (int x): a(x)      /* Initializer list must be used */
      {
    
      }
     };

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

 1. Default constructor of Sample1 class
 2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
  1. क्लास कंस्ट्रक्टर का पैरामीटर नाम और क्लास का डेटा सदस्य समान हैं:

     class Sample3 {
        int i;         /* Member variable name : i */  
        public:
        Sample3 (int i)    /* Local variable name : i */ 
        {
            i = i;
            print(i);   /* Local variable: Prints the correct value which we passed in constructor */
        }
        int getI() const 
        { 
             print(i);    /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
             return i; 
        }
     };

जैसा कि हम सभी जानते हैं कि स्थानीय चर सर्वोच्च प्राथमिकता वाले वैश्विक चर हैं यदि दोनों चर समान नाम वाले हैं। इस स्थिति में, प्रोग्राम "i" मान {बाएं और दाएं दोनों तरफ चर। यानी: i = i} नमूना 3 में स्थानीय चर के रूप में () निर्माता और वर्ग सदस्य चर (i) ओवरराइड हो गया। से बचने के लिए, हमें या तो उपयोग करना चाहिए

  1. Initialization list 
  2. this operator.

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