2008-12-04 10 views
7

मैं अपने C++ अनुप्रयोग में इस तरह स्ट्रिंग के आसपास पारित करने के लिए प्रयोग किया जाता है:सी ++ स्ट्रिंग है जो शून्य हो सकता है

void baz() 
{ 
    foo("stackoverflow"); 
    foo(NULL); // very bad with foo implementation above 
} 
:

void foo(const std::string& input) 
{ 
    std::cout << input.size() << std::endl; 
} 

void bar() 
{ 
    foo("stackoverflow"); 
} 

अब मैं एक मामले में जहां मैं स्ट्रिंग शून्य होना चाहते है

मैं करने के लिए foo को बदल सकता है:

void foo(const std::string* input) 
{ 
    // TODO: support NULL input 
    std::cout << input->size() << std::endl; 
} 

लेकिन एक स्ट्रिंग शाब्दिक पारित करने के लिए या एककॉपी foo की कि कार्यान्वयन के लिए 0 मैं कुछ इस तरह लिखने की ज़रूरत:

void bar() 
{ 
    string input("hi"); // annoying temporary 
    foo(&input); 
    foo(NULL); // will work as long as foo handles NULL properly 
} 

मैं std::string से इनहेरिट और एक null संपत्ति जोड़ने के बारे में सोचना शुरू कर दिया है, लेकिन मैं इतना यकीन है कि यह एक अच्छा विचार है नहीं कर रहा हूँ। हो सकता है कि पैरामीटर के लिए const char* स्ट्रिंग का उपयोग करना बेहतर हो जो कि नल हो सकता है, लेकिन अगर मैं स्ट्रिंग (या न्यूल) की एक प्रति सहेजने के बिना अपनी याददाश्त को सहेजना चाहता हूं तो क्या होगा? (What are some of the drawbacks to using C-style strings? आदि देखें)

आसपास के किसी भी चालाक समाधान?

+0

आप एक पूर्ण क्यों चाहते हैं? काफी है? – Tim

+0

@Tim: शायद। यह मुझे हमेशा के लिए उन पैरामीटर की जांच करने से बचाएगा, और मैं "कोई मूल्य" की जांच करने के लिए खाली() का उपयोग नहीं करता। –

+0

न्यूल पुन: प्रस्तुत करना फर्जी है। यदि आपको भयानक नल पॉइंटर की आवश्यकता है तो आप पहली जगह संदर्भों का उपयोग क्यों कर रहे हैं? असल में संदर्भों का उपयोग करने के सबसे महत्वपूर्ण कारणों में से एक यह है कि आप सुनिश्चित कर सकते हैं कि यह पूर्ण नहीं है। – Thorsten79

उत्तर

20

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

वैकल्पिक रूप से, बूस्ट :: वैकल्पिक का उपयोग करें, जो "यह चर निर्दिष्ट कर सकता है या नहीं हो सकता है" निर्दिष्ट करने के लिए एक और प्रकार-सुरक्षित तरीका की अनुमति देता है।

या, ज़ाहिर है, अर्थशास्त्र को बदलें ताकि आप या तो शून्य के बजाय खाली तारों का उपयोग कर सकें, स्ट्रिंग उपलब्ध है या नहीं, या रिफैक्टर को निर्दिष्ट करने के लिए एक अलग बूल पैरामीटर पास करें ताकि आपको पहले स्थान की आवश्यकता न हो।

+0

+1 मुझे बढ़ावा देने के बारे में जानकारी देने के लिए :: वैकल्पिक –

1

क्या होगा अगर तुम सिर्फ का उपयोग करें:

void foo(const char *xinput) 
{ 
    if (xinput == NULL) { 
     // do something exceptional with this 
     return; 
    } 
    std::string input(xinput); 
    // remainder of code as usual 
} 

हाँ, यह एक अतिरिक्त आवंटन और प्रतिलिपि उठाना होता है, और कार्यप्रणाली को कॉल में थोड़ा और अधिक वर्बोज़ है, क्योंकि आप हमेशा की तरह मामले में .c_str() उपयोग करने की आवश्यकता है, लेकिन यह आपको वह अर्थशास्त्र देता है जो आप चाहते हैं।

11

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

void foo(const std::string& input) 
{ 
    if (!input.empty()) 
     std::cout << input.size() << std::endl; 
} 

void bar() 
{ 
     foo(""); 
} 
+1

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

+0

खाली() का उपयोग करने के लिए बदला गया। मूल प्रश्न पर एक टिप्पणी "मूल्य को नहीं जानते" और "खाली मूल्य" को इंगित करने के लिए खाली करने के लिए NULL का उपयोग करने के लिए इंगित करती है। जो इस जवाब को गलत बनाता है। लेकिन मैं चीजों पर एक दूसरी नजर डालेगा क्योंकि पॉइंटर्स के चारों ओर गुज़रने से "इस सूचक का मालिक कौन है?" समस्या का। –

+0

या तो बूस्ट :: वैकल्पिक या स्मार्ट पॉइंटर उस मामले में सबसे अच्छा विकल्प होगा। –

2

आप फ़ंक्शन को अधिभार क्यों नहीं देते हैं और दूसरा अधिभार कोई तर्क नहीं देते हैं? फिर दोनों अधिभार आंतरिक रूप से एक फ़ंक्शन को कॉल कर सकते हैं जो पढ़ने के तर्क प्रदान करता है और वह स्वयं, std::string पर एक सूचक पारित हो जाता है।

void foo_impl(string const* pstr) { … } 

void foo(string const& str) { 
    foo_impl(&str); 
} 

void foo() { 
    foo_impl(0); 
} 
11

समारोह बचाव के लिए अधिक भार ...

void foo(const std::string& input) 
{ 
    std::cout << input << std::endl; 

    // do more things ... 
} 

void foo(const char* input) 
{ 
    if (input != NULL) foo(std::string(input)); 
} 

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

+1

मैं ऐसा नहीं करता, यह भ्रामक हो सकता है। – sudarkoff

+0

यही बात है, वास्तव में; यह एक अमूर्त है। उपयोग सरल होना चाहिए, जब तक कि आप प्रदर्शन के बारे में बेहद चिंतित न हों। – eplawless

+1

@ सुडारॉफ: मैं असहमत हूं। समस्या स्वयं भ्रामक है, और एक अमूर्त की जरूरत है। समाधान सुरुचिपूर्ण है। प्रदर्शन समस्या के बारे में, "समयपूर्व अनुकूलन, आदि" ... +1। – paercebal

3

या, दो पिछले जवाब का एक सा मिश्रण:

void fooImpl(const char* input) 
{ 
    if (input != NULL) 
     std::cout << input << std::endl; 
} 

void foo(const std::string& input) 
{ 
    fooImpl(input.c_str());  
} 

void foo(const char* input) 
{ 
    fooImpl(input); 
} 

एक ही इंटरफ़ेस, स्टैक पर कोई प्रति नहीं। यदि आप पसंद करते हैं, तो आप इनलाइन fooImpl भी इनलाइन कर सकते हैं।

2

बिल्कुल std::string से प्राप्त नहीं है। विरासत सी ++ में आपके पास सबसे सख्त युग्मन है, और आप केवल शून्यता की तलाश कर रहे हैं, जिसे आप वास्तव में const char*, अधिभार, या बस std::string * के साथ प्राप्त कर सकते हैं यदि आप वास्तव में चाहते हैं।

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