C ++ स्ट्रक्चर्स को इनिशियलाइज़ करने का उचित तरीका


82

हमारे कोड में एक POD (Plain Old Datastructure) संरचना शामिल है (यह एक बुनियादी c ++ संरचना है जिसमें अन्य संरचनाएं और POD चर हैं जिन्हें शुरुआत में आरंभ करने की आवश्यकता है।)

मैंने जो पढ़ा है , उसके आधार पर ऐसा लगता है कि:

myStruct = (MyStruct*)calloc(1, sizeof(MyStruct));

सभी मानों को शून्य से आरंभ करना चाहिए, जैसा कि निम्नानुसार है:

myStruct = new MyStruct();

हालांकि, जब दूसरे तरीके से संरचना को शुरू किया जाता है, तो Valgrind बाद में "सशर्त कूद या चाल की पुष्टि करता है, जो कि उन चरों का उपयोग किए जाने पर असमान मूल्य पर निर्भर करता है।" क्या मेरी समझ यहाँ त्रुटिपूर्ण है, या वाल्ग्रिंड झूठी सकारात्मकता फेंक रहा है?


1
यह भी ध्यान दें कि new MyStruct()C ++ 03 में किसी भी पेडिंग बाइट को सेट करने के लिए आवश्यक नहीं था। C ++ 0x में यह है। कोई भी पेडिंग बिट्स C ++ 0x में 0 पर सेट हो जाएगा।
जोहान्स स्काउब -

पकड़ के लिए धन्यवाद, मैंने अपना प्रश्न संपादित किया।
शैडोहॉक

Releated पूछे जाने वाले प्रश्न: stackoverflow.com/questions/620137/...
Robᵩ

जैसा कि मैं चीजों को समझता हूं, आपको वह त्रुटि संदेश नहीं मिलना चाहिए। शायद आपकी डेटा संरचना POD नहीं है? क्या आप अपने कोड को सबसे छोटे प्रोग्राम में घटा सकते हैं जो अभी भी इस व्यवहार को प्रदर्शित करता है, और उस आसुत प्रोग्राम को पोस्ट करता है? (देखें sscce.org )।
रोबो

क्या संकलक? क्या आप MyStruct की परिभाषा पोस्ट कर सकते हैं?
एलन स्टोक्स

जवाबों:


121

सी ++ में कक्षाएं / संरचनाएं समान हैं (प्रारंभिक के संदर्भ में)।

एक गैर POD संरचना में एक निर्माता हो सकता है इसलिए यह सदस्यों को आरंभ कर सकता है।
यदि आपकी संरचना एक POD है तो आप एक इनिलाइज़र का उपयोग कर सकते हैं।

struct C
{
    int x; 
    int y;
};

C  c = {0}; // Zero initialize POD

वैकल्पिक रूप से आप डिफ़ॉल्ट कंस्ट्रक्टर का उपयोग कर सकते हैं।

C  c = C();      // Zero initialize using default constructor
C  c{};          // Latest versions accept this syntax.
C* c = new C();  // Zero initialize a dynamically allocated object.

// Note the difference between the above and the initialize version of the constructor.
// Note: All above comments apply to POD structures.
C  c;            // members are random
C* c = new C;    // members are random (more officially undefined).

मेरा मानना ​​है कि वैलग्राइंड को शिकायत है क्योंकि सी ++ काम कैसे करता था। (जब सी ++ को जीरो इनिशियलाइज़ेशन डिफॉल्ट कंस्ट्रक्शन के साथ अपग्रेड किया गया था) मुझे बिलकुल यकीन नहीं है। आपका सबसे अच्छा शर्त एक निर्माता को जोड़ना है जो ऑब्जेक्ट को इनिशियलाइज़ करता है (स्ट्रक्चर को अनुमति दी जाती है)।

एक साइड नोट के रूप में:
बहुत से शुरुआती लोग init को महत्व देते हैं:

C c(); // Unfortunately this is not a variable declaration.
C c{}; // This syntax was added to overcome this confusion.

// The correct way to do this is:
C c = C();

"मोस्ट वैक्सिंग पार्स" के लिए एक त्वरित खोज, मैं जितना कर सकता हूं उससे बेहतर स्पष्टीकरण प्रदान करेगा।


1
क्या आपके पास C ++ में चर के इस शून्य-प्रारंभिककरण के लिए एक संदर्भ है? पिछले मैंने सुना है, यह अभी भी सी। IIRC के समान व्यवहार करता है, MSVC संकलक ने शून्य-प्रारंभिक असंगठित सदस्यों को कुछ बिंदु पर (प्रदर्शन कारणों से, मुझे लगता है) गिरा दिया, जो स्पष्ट रूप से अन्य एमएस डिवीजनों के लिए गंभीर रूप से गंभीर समस्याएं पैदा कर रहे थे :)
मार्क मुत्ज़ - mmutz

1
नहीं, नहीं, C()लेकिन ऐसा लगता है कि आप सही हैं
मार्क मुत्ज़ - mmutz

4
POD वर्ग के साथ T, T()ने हमेशा स्केलर सबोबिज को शून्य किया है। टॉपप्ले आरंभीकरण के नाम को C ++ 03 की तुलना में C ++ 98 में अलग कहा गया था ("डिफ़ॉल्ट आरंभीकरण" बनाम "मूल्य आरंभीकरण"), लेकिन POD के लिए अंतिम प्रभाव समान हैं। C ++ 98 और C ++ 03 दोनों में सभी मान शून्य होंगे।
जोहान्स स्काउब -

1
@RockyRaccoon C c();दुर्भाग्य से एक परिवर्तनीय घोषणा नहीं है, बल्कि एक फ़ंक्शन का एक आगे की घोषणा (ए फ़ंक्शन जिसे 'सी' कहा जाता है जो कोई पैरामीटर नहीं लेता है और टाइप सी का ऑब्जेक्ट लौटाता है)। Google: मोस्ट वैक्सिंग पार्स
मार्टिन यॉर्क

1
@RockyRaccoon यहाँ अंतर और सवाल के साथ आप अपनी टिप्पणी में लिंक; यह है कि इस मामले में कसौटी में इस्तेमाल कोई पैरामीटर नहीं हैं। इसलिए कंपाइलर के पास इसे पार्स करने और किसी फ़ंक्शन के वेरिएबल डिक्लेरेशन और फ़ॉरवर्ड डिक्लेरेशन के बीच अंतर बताने का कठिन समय होता है। यह आगे की घोषणा को चुनता है। यदि आपको कंस्ट्रक्टर में एक पैरामीटर की आवश्यकता होती है, तो संकलक देख सकता है कि यह बिना किसी समस्या के एक चर घोषणा है। C c(4);एक मान्य चर घोषणा है।
मार्टिन यॉर्क

2

आपने हमें जो बताया है, उससे यह वैलेग्रिड में एक झूठी सकारात्मकता प्रतीत होती है। के newसाथ वाक्य रचना() वस्तु मूल्य आरंभ कर देना चाहिए, यह मानते हुए यह पॉड है।

क्या यह संभव है कि आपकी संरचना के कुछ सबपार्टर वास्तव में POD नहीं हैं और यह अपेक्षित आरंभ को रोक रहा है? क्या आप अपने कोड को एक पोस्ट करने योग्य उदाहरण में सरल बनाने में सक्षम हैं जो अभी भी वैध त्रुटि को चिह्नित करता है?

वैकल्पिक रूप से शायद आपका कंपाइलर वास्तव में POD स्ट्रक्चर्स को महत्व नहीं देता है।

किसी भी मामले में संभवत: सबसे सरल समाधान है कंस्ट्रक्टर (ओं) को लिखना, जैसा कि संरचना / उपप्रकारों के लिए आवश्यक है।


1

मैं कुछ परीक्षण कोड लिखता हूं:

#include <string>
#include <iostream>
#include <stdio.h>

using namespace std;

struct sc {
    int x;
    string y;
    int* z;
};

int main(int argc, char** argv)
{
   int* r = new int[128];
   for(int i = 0; i < 128; i++ ) {
        r[i] = i+32;
   }
   cout << r[100] << endl;
   delete r;

   sc* a = new sc;
   sc* aa = new sc[2];
   sc* b = new sc();
   sc* ba = new sc[2]();

   cout << "az:" << a->z << endl;
   cout << "bz:" << b->z << endl;
   cout << "a:" << a->x << " y" << a->y << "end" << endl;
   cout << "b:" << b->x << " y" << b->y <<  "end" <<endl;
   cout << "aa:" << aa->x << " y" << aa->y <<  "end" <<endl;
   cout << "ba:" << ba->x << " y" << ba->y <<  "end" <<endl;
}

जी ++ संकलित करें और चलाएं:

./a.out 
132
az:0x2b0000002a
bz:0
a:854191480 yend
b:0 yend
aa:854190968 yend
ba:0 yend

ठीक है, मैं new sc;बनाम से परिचित नहीं हूँ new sc();। मुझे लगता है कि लापता परियों में एक त्रुटि थी। लेकिन यह प्रदर्शित करने के लिए लगता है कि उत्तर सही है (जब आप डिफ़ॉल्ट कंस्ट्रक्टर का उपयोग करते हैं तो यह 0 से init करता है।)
nycynik

0

आपको अपनी संरचना में जो भी सदस्य हैं, उन्हें आरंभ करने की आवश्यकता है, जैसे:

struct MyStruct {
  private:
    int someInt_;
    float someFloat_;

  public:
    MyStruct(): someInt_(0), someFloat_(1.0) {} // Initializer list will set appropriate values

};

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

एक संरचना एक वर्ग है। मेरी पोस्ट का संपादन किया :)
ralphtheninja

2
आपको POD के लिए यह करने की आवश्यकता नहीं है
एलन स्टोक्स

0

चूँकि यह एक POD संरचना है, आप इसे हमेशा 0 पर ही रद्द कर सकते हैं - यह आरंभिक क्षेत्रों को प्राप्त करने का सबसे आसान तरीका हो सकता है (यह मानते हुए कि यह उपयुक्त है)।


1
चाहे वह एक संरचना हो या एक वर्ग का निर्माण करने या निर्माण करने की क्षमता से कोई लेना-देना नहीं है। उदाहरण के लिए देखें stackoverflow.com/questions/2750270/cc-struct-vs-class
एरिक

आप इसे बनाने के बाद आम तौर पर एक वर्ग को याद नहीं करेंगे, क्योंकि इसके निर्माता (संभवतः) ने आरंभीकरण किया था।
स्कॉट सी विल्सन

1
डिफ़ॉल्ट सुरक्षा (निजी और सार्वजनिक, सम्मान) को छोड़कर, C ++ में "वर्ग" और "संरचना" के बीच कोई अंतर नहीं है। एक संरचना एक गैर-पीओडी हो सकती है और एक कक्षा एक पीओडी हो सकती है, ये अवधारणाएं ऑर्थोगोनल हैं।
मार्क मुत्ज़ - मिमीटज़

@mmutz और @ एरिक - सहमत - भ्रम को रोकने के लिए मेरे जवाब को छोटा कर दिया।
स्कॉट सी विल्सन

memset () सबसे अच्छा विकल्प नहीं है, आप केवल अपने डिफ़ॉल्ट ctor को कॉल करके एक POD संरचना को शून्य-आरंभ कर सकते हैं।
निल्स

0

यह मुझे सबसे आसान तरीका लगता है। संरचना सदस्यों को घुंघराले ब्रेसिज़ '{}' का उपयोग करके आरंभ किया जा सकता है। उदाहरण के लिए, निम्नलिखित एक मान्य प्रारंभ है।

struct Point 
{ 
   int x, y; 
};  

int main() 
{ 
   // A valid initialization. member x gets value 0 and y 
   // gets value 1.  The order of declaration is followed. 
   struct Point p1 = {0, 1};  
}

C ++ में स्ट्रक्चर्स के बारे में अच्छी जानकारी है - https://www.geeksforgeeks.org/structures-in-cpp/

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