2010-05-14 17 views
17

अक्सर डेटा संरचनाओं का वैध प्रारंभ सभी सदस्यों को शून्य पर सेट करना है। सी ++ में प्रोग्रामिंग करते समय भी, किसी बाहरी एपीआई के साथ इंटरफेस करने की आवश्यकता हो सकती है जिसके लिए यह मामला है।सभी शून्यों पर किसी ऑब्जेक्ट को प्रारंभ करना

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

some_struct s; 
memset(&s, 0, sizeof(s)); 

और बस

some_struct s = { 0 }; 

? (उम्मीद है कि यह समझा जाता है कि यह केवल वर्तमान में पीओडी संरचनाओं पर लागू होता है; यदि उस संरचना में सी ++ std :: स्ट्रिंग थी तो आपको सभी तरह के विनाश मिलेगा।)

मेरे लिए, ज्यादातर सी ++ प्रोग्रामर के रूप में मेमसेट का अधिक उपयोग नहीं करता है, मैं कभी भी फ़ंक्शन हस्ताक्षर के कुछ नहीं हूं, इसलिए मुझे लगता है कि दूसरा उदाहरण कम टाइपिंग, अधिक कॉम्पैक्ट, और इससे भी अधिक स्पष्ट होने के अलावा उपयोग करना आसान है क्योंकि यह "ऑब्जेक्ट" कोड की अगली पंक्ति की प्रतीक्षा करने और देखने के बजाए घोषणा में सही "शून्य में शुरू किया गया है," ओह, यह ऑब्जेक्ट शून्य प्रारंभ हुआ है। "

सी ++ में कक्षाएं और structs बनाते समय मैं प्रारंभिक सूचियों का उपयोग करता हूं; मैं सी ++ में उपलब्ध होने के मुकाबले तुलना में उपरोक्त दो "सी स्टाइल" प्रारंभिकताओं पर लोगों के विचारों के बारे में उत्सुक हूं क्योंकि मुझे सी पुस्तकालयों के साथ कई इंटरफ़ेस पर संदेह है, भले ही हम ज्यादातर सी ++ में कोड करते हैं।

संपादित करें: नील बटरवर्थ this question उत्पन्न, फॉलोअप में, मुझे विश्वास है कि इस सवाल का एक दिलचस्प परिणाम है।

+1

सी ++ में, शून्य प्रारंभिकता अधिक कार्यात्मक उपयोग नहीं करती है, क्योंकि कन्स्ट्रक्टर यह सुनिश्चित करेगा कि यह प्रकार जाने के लिए तैयार है। – Puppy

+0

@DeadMG: पीओडी प्रकार के निर्माता क्या करते हैं? –

+0

@ डैश-टॉम-बैंग: यह बिल्कुल कुछ भी नहीं करता है। – AnT

उत्तर

22

memset व्यावहारिक रूप से ऐसा करने का सही तरीका नहीं है। और हाँ, एक व्यावहारिक अंतर है (नीचे देखें)।

सी में सब कुछ शाब्दिक 0 साथ प्रारंभ ++ नहीं जा सकता है (enum प्रकार की वस्तुओं नहीं किया जा सकता), जिसके कारण C++ आम मुहावरा

some_struct s = {}; 

है, जबकि सी में मुहावरा

है
some_struct s = { 0 }; 

नोट, कि = { 0 } सी में सार्वभौमिक शून्य प्रारंभकर्ता कहा जा सकता है। यह वास्तव में किसी भी प्रकार की वस्तुओं के साथ इस्तेमाल किया जा सकता क्योंकि {} -enclosed initializers जो उदाहरण के लिए = { 0 } सामान्य प्रकार स्वतंत्र सी कोड में उपयोगी (प्रकार स्वतंत्र मैक्रो बनाता अदिश वस्तुओं के रूप में अच्छी तरह से

int x = { 0 }; /* legal in C (and in C++) */ 

साथ अनुमति दी जाती है)।

= { 0 } सी 8 9/9 0 और सी ++ में प्रारंभकर्ता का दोष यह है कि इसे केवल घोषणा के एक हिस्से के रूप में उपयोग किया जा सकता है। (सी 99 ने यौगिक अक्षर प्रस्तुत करके इस समस्या को ठीक किया है। इसी तरह की कार्यक्षमता सी ++ में भी आ रही है।) इस कारण से आप कई प्रोग्रामर memset का उपयोग कर सकते हैं ताकि सी 8 9/9 0 या सी ++ कोड के मध्य में कुछ शून्य हो सके। फिर भी, मैं कहेंगे कि ऐसा करने के लिए उचित तरीके से memset बिना अब भी है बल्कि

some_struct s; 
... 
{ 
    const some_struct ZERO = { 0 }; 
    s = ZERO; 
} 
... 

कोड के बीच में एक "कल्पित" ब्लॉक शुरू करने से यानी की तरह कुछ के साथ, भले ही यह भी देखने के लिए नहीं हो सकता है पहली नजर में सुंदर। बेशक, सी ++ में ब्लॉक को पेश करने की कोई आवश्यकता नहीं है।

व्यावहारिक अंतर के लिए ... आप कुछ लोगों को यह कह सकते हैं कि memset अभ्यास में एक ही परिणाम उत्पन्न करेगा, क्योंकि व्यावहारिक रूप से भौतिक ऑल-शून्य बिट पैटर्न का उपयोग सभी प्रकार के शून्य मूल्यों का प्रतिनिधित्व करने के लिए किया जाता है। हालांकि, यह आम तौर पर सच नहीं है। एक तत्काल उदाहरण है कि एक विशिष्ट सी ++ कार्यान्वयन में अंतर का प्रदर्शन होगा एक सूचक करने वाली डेटा सदस्यीय प्रकार

struct S; 
... 

int S::*p = { 0 }; 
assert(p == NULL); // this assertion is guaranteed to hold 

memset(&p, 0, sizeof p); 
assert(p == NULL); // this assertion will normally fail 

यह इसलिए होता है क्योंकि एक विशिष्ट कार्यान्वयन आम तौर पर सभी एक सा पैटर्न (0xFFFF...) का प्रतिनिधित्व करने का उपयोग करता है इस प्रकार के शून्य सूचक। उपरोक्त उदाहरण शून्यिंग memset और सामान्य = { 0 } प्रारंभकर्ता के बीच एक वास्तविक जीवन व्यावहारिक अंतर दर्शाता है।

+1

@AndreyT: '" बेशक, सी ++ में ब्लॉक को पेश करने की कोई आवश्यकता नहीं है ", क्यों? इसके अलावा, आप सी में ब्लॉक क्यों पेश करना चाहते हैं? – Lazer

+1

@eSKay: क्योंकि सी ++ कोड के बीच में घोषणाएं जोड़ने की अनुमति देता है। ब्लॉक के लिए कोई ज़रूरत नहीं है। सी 99 भी इसके साथ ही अनुमति देता है, लेकिन जैसा कि मैंने सी 99 में ऊपर कहा था, आपके पास बेहतर विकल्प है: यौगिक अक्षर। अनदेखा छोड़ दिया गया एकमात्र मामला सी 8 9/9 0 है। सी 8 9/9 0 में आप कोड के बीच में एक चर घोषित नहीं कर सकते हैं। आपको एक ब्लॉक की जरूरत है। यही कारण है कि मैं सी में एक ब्लॉक शुरू करना चाहता हूं (सी 8 9/9 0 का मतलब है)। – AnT

+0

@AndreyT: धन्यवाद! कभी नहीं पता था कि "सी 8 9/9 0 में आप कोड के बीच में एक चर घोषित नहीं कर सकते हैं"। लेकिन मैंने 'gcc -std = c89 check89.c' का उपयोग करके [इस कोड] (http://codepad.org/nx3vzW1o) का परीक्षण किया, और यह संकलित और ठीक चलाता है! – Lazer

15

some_struct s = { 0 }; काम करने की गारंटी है; memset कार्यान्वयन विवरण पर निर्भर करता है और सबसे अच्छा बचा जाता है।

+4

यदि यह सी ++ के बारे में है, तो नहीं, यह * कुछ * काम नहीं करेगा जब 'some_struct' का पहला सदस्य एक enum ऑब्जेक्ट है। यह सी ++ में '= {}' प्रारंभकर्ताओं को पेश किए जाने के कारणों में से एक है। – AnT

6

struct संकेत दिए गए हैं, तो सभी बिट्स के रूप में memset द्वारा उत्पादित शून्य का मूल्य सी (या सी ++) कोड है, यानी एक NULL सूचक में इसे करने के लिए एक 0 बताए के रूप में ही इसका मतलब यह नहीं हो सकता है।

(।। यह भी floats और doubles के मामले में हो सकता है, लेकिन यह है कि मैं कभी नहीं का सामना किया है लेकिन, मुझे नहीं लगता कि मानकों उन्हें गारंटी शून्य memset साथ बनने के लिए या तो)

संपादित करें: एक और व्यावहारिक परिप्रेक्ष्य से, मैं अभी भी memset का उपयोग करने के लिए कहने के लिए कहूंगा, क्योंकि यह एक अतिरिक्त फ़ंक्शन कॉल है, लिखने में लंबा है, और (मेरी राय में) = { 0 } से अधिक इरादे से कम स्पष्ट है।

+2

सी और सी ++ मानकों को फ्लोटिंग पॉइंट नंबर के रूप में 0.0 में बदलने के लिए सभी बिट्स शून्य की आवश्यकता नहीं है, लेकिन आईईईई मानक करते हैं। ऐसी मशीनें हैं जो आईईईई मानकों का पालन नहीं करती हैं, लेकिन जिनमें से सभी मुझे पता है कि सभी बिट्स शून्य से 0.0 तक परिवर्तित होते हैं। –

+1

प्रश्न * व्यावहारिक * अंतर के लिए पूछा गया। व्यावहारिक रूप से बोलते हुए, शून्य पॉइंटर्स हमेशा सभी बिट्स-शून्य होते हैं, और फ़्लोटिंग-पॉइंट प्रकारों के शून्य मान भी होते हैं। –

+0

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

5

कंपाइलर अनुकूलन के आधार पर, कुछ थ्रेसहोल्ड हो सकता है जिसके ऊपर मेमसेट तेज है, लेकिन यह आम तौर पर स्टैक आधारित चर के सामान्य आकार से ऊपर होगा। वर्चुअल टेबल के साथ एक C++ ऑब्जेक्ट पर मेमसेट का उपयोग करना बिल्कुल खराब है।

+0

किसी भी गैर-पीओडी पर 'मेमसेट' का उपयोग करना बुरा है। साथ ही, यदि कुछ प्रारंभ करने के लिए 'मेमसेट' तेज है, तो मुझे नहीं लगता कि संकलक फिर ऐसी चीज़ के लिए '= {}' को अनुकूलित क्यों नहीं करेगा। – GManNickG

0

bzero फ़ंक्शन एक और विकल्प है।

#include <strings.h> 
void bzero(void *s, size_t n); 
+2

'bzero' मानक नहीं है और सभी प्लेटफ़ॉर्म पर उपलब्ध नहीं हो सकता है। हरबिसन और स्टील से: "अधिक प्रतिबंधित कार्य 'बजेरो' ... कुछ यूनिक्स कार्यान्वयन में पाया जाता है।" यह नहीं बताता है कि समारोह सभी कार्यान्वयन में उपलब्ध है। –

3

केवल व्यावहारिक अंतर यह है कि ={0}; वाक्य रचना कहा, "प्रारंभ इस खाली होने के लिए" के बारे में थोड़ा स्पष्ट है (कम से कम यह मेरे लिए स्पष्ट लगता है) है।

शुद्ध रूप से सैद्धांतिक रूप से, ऐसी कुछ स्थितियां हैं जिनमें memset विफल हो सकता है, लेकिन जहां तक ​​मुझे पता है, वे वास्तव में केवल यही हैं: सैद्धांतिक। ओटीओएच, यह देखते हुए कि यह एक सैद्धांतिक और दोनों से एक व्यावहारिक दृष्टिकोण है, मुझे यह पता लगाना मुश्किल है कि कोई भी इस कार्य के लिए memset का उपयोग क्यों करना चाहता है।

+0

'स्मृति' वास्तविक वातावरण में '= {}' से अधिक विफल रहता है। (मुझे नहीं पता कि नाम क्या हैं, लेकिन मुझे पता है कि वे मौजूद हैं। और वे आधुनिक हैं।) – GManNickG

+0

@GMan: मुझे कुछ वातावरण के बारे में पता है जिसमें एक शून्य सूचक के सामान्य प्रतिनिधित्व में सभी बिट्स शून्य नहीं हैं - लेकिन कम से कम जिनके बारे में मुझे पता है, सभी बिट्स-शून्य * करता है * एक शून्य पॉइंटर भी बनाता है। बेशक, ऐसी मशीनें हैं जिनका मैंने उपयोग नहीं किया है। जैसा कि मैंने कहा, भले ही मैं इसे विफल करने पर ध्यान नहीं दे सकता, फिर भी मैं 'स्मृति' का उपयोग करने के लिए एक अच्छे कारण की कल्पना नहीं कर सकता। –

+2

आप बहुत सावधानी से नहीं देख रहे हैं। वस्तुतः सभी लोकप्रिय सी ++ कार्यान्वयन (उदाहरण के लिए, जी ++ शामिल है) सी ++ में * पॉइंटर-टू-डेटा-सदस्य * प्रकार के नल पॉइंटर्स के लिए ** सभी-** ** बिट पैटर्न का उपयोग करें। कुछ वर्ग प्रकार 'एस' के लिए' int S :: * p' की तरह। आपको ऐसे सूचक के साथ 'मेमसेट (और पी, 0, आकार पी) 'करके एक शून्य सूचक प्राप्त नहीं होगा। – AnT

2

मैंने सबकुछ शून्य पर सेट करने की रहस्यमय भलाई को कभी नहीं समझा है, भले ही इसे परिभाषित किया गया हो, वांछित होने की संभावना नहीं है। चूंकि इसे सी ++ के रूप में टैग किया गया है, प्रारंभिकरण का सही समाधान स्ट्रक्चर या कक्षा को एक कन्स्ट्रक्टर देना है।

+1

सी में लिखे गए तृतीय-पक्ष पुस्तकालयों से निपटने पर एक कठिन पंक्ति की तरह लग रहा है, जिसके लिए आपके पास स्रोत कोड नहीं है। –

+0

यदि आपकी संरचना में संरचना के स्वामित्व वाले पॉइंटर्स हैं, तो यह कम मनमाना है, तब से एक क्लीनअप फ़ंक्शन बिना शर्त के 'मुक्त' (या 'हटाएं') को कॉल कर सकता है। – jamesdlin

2

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

सी ++, मेमसेट, मॉलोक & सह के साथ काम करने वाले कुछ लोगों के लिए। काफी गूढ़ प्राणी हैं। मुझे कुछ खुद का सामना करना पड़ा है।

+0

मैं सहमत हूं- मैं इंतजार नहीं कर सकता, तारांकन के साथ कि मैं इस बारे में चिंतित हूं कि जब ऐसा होता है तो संकलक विक्रेता हमारे ऊपर क्या छोड़ते हैं। (कंपाइलर विक्रेताओं के लिए एक छोटे से बाजार के साथ "गूढ़" प्लेटफार्मों पर काम करने वाले किसी व्यक्ति के रूप में बोलना।) –

2

संरचनाओं समाशोधन के लिए सबसे अच्छा तरीका प्रत्येक क्षेत्र अलग-अलग सेट करने के लिए है: ऊपर के उदाहरण में

struct MyStruct 
{ 
    std::string name; 
    int age; 
    double checking_account_balance; 
    void clear(void) 
    { 
    name.erase(); 
    age = 0; 
    checking_account_balance = 0.0; 
    } 
}; 

, एक clear विधि एक ज्ञात राज्य या मूल्य के लिए सभी सदस्यों को स्थापित करने के लिए परिभाषित किया गया है। memset और std::fill विधियां std::string और double प्रकारों के कारण काम नहीं कर सकती हैं। एक और मजबूत कार्यक्रम व्यक्तिगत रूप से प्रत्येक क्षेत्र को साफ़ करता है।

मुझे कम समय टाइपिंग खर्च करने से अधिक मजबूत कार्यक्रम पसंद है।

3

Hopefully it is understood that this is only currently available for POD structures; you'd get a compiler error if there was a C++ std::string in that structure.

नहीं, तुम नहीं होगा। यदि आप इस पर memset का उपयोग करते हैं, तो सबसे अच्छा आप केवल दुर्घटनाग्रस्त हो जाएंगे, और सबसे बुरी स्थिति में आपको कुछ गड़बड़ हो जाएगी। = { } तरीके गैर-पीओडी structs पर पूरी तरह से ठीक इस्तेमाल किया जा सकता है, जब तक वे एकत्रित होते हैं। = { } तरीका सी ++ में लेने का सबसे अच्छा तरीका है। कृपया ध्यान दें कि C++ डाल करने के लिए है कि 0 उस में कोई कारण नहीं है, न ही यह, की सिफारिश की है, क्योंकि यह काफी मामलों में यह प्रयोग किया जा सकता

struct A { 
    std::string a; 
    int b; 
}; 

int main() { 
    A a = { 0 }; 
    A a = { }; 
} 

पहले आप क्या चाहते हैं काम नहीं चलेगा कम कर देता है कि: यह एक सी-स्ट्रिंग से std::string बनाने के लिए अपने कन्स्ट्रक्टर को एक शून्य सूचक देने की कोशिश करेगा। दूसरा, हालांकि, आप जो चाहते हैं वह करता है: यह एक खाली स्ट्रिंग बनाता है।

+0

आह पर्याप्त मेला; मैं उस संपादन को हटा दूंगा। "गैर-समेकितों की मेरी याददाश्त को आरंभकर्ता सूची के साथ प्रारंभ नहीं किया जा सकता" त्रुटियों में मेरी सोच क्लाउड ... बेशक, कोई भी ऑब्जेक्ट जिसमें एक भी तर्क (गैर-स्पष्ट?) Ctor होगा, यह व्यवहार होगा। Std :: स्ट्रिंग के मामले में, खुशी से स्ट्रिंग ऑप्स न्यूल से कर रहे हैं। –

0

सी में मैं {0,} समकक्ष स्मृति() पर उपयोग करना पसंद करता हूं। हालांकि जीसीसी इस प्रयोग के बारे में चेतावनी दी है :(यहाँ विवरण: http://www.pixelbeat.org/programming/gcc/auto_init.html

C++ में वे आम तौर पर बराबर कर रहे हैं, लेकिन हमेशा की तरह सी ++ साथ कोने मामलों पर विचार करने के (अन्य उत्तर में बताया गया है) देखते हैं

4

मैं। एक अच्छा समाधान हो पाया:

template<typename T> void my_zero(T& e) { 
    static T dummy_zero_object; 
    e = dummy_zero_object; 
} 

my_zero(s); 

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

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