2013-07-04 7 views
15

से std::string प्रारंभ करना char पॉइंटर अपरिभाषित व्यवहार है, मुझे विश्वास है कि std :: स्ट्रिंग प्रारंभ करें।संभावित रूप से नल चार सूचक

void MyClass::MyClass(const char *cstr) : 
    mStdString(cstr ? cstr : "") 
{} 

void MyClass::MyClass(const char *cstr) : 
    mStdString(cstr ? std::string(cstr) : std::string()) 
{} 

void MyClass::MyClass(const char *cstr) 
{ 
    if (cstr) mStdString = cstr; 
    // else keep default-constructed mStdString 
} 

संपादित करें, class MyClass अंदर निर्माता घोषणा:: तो, यहाँ एक निर्माता है, जहां mStdString प्रकार std::string के एक सदस्य चर रहा है के वैकल्पिक संस्करण हैं और कुछ

MyClass(const char *cstr = NULL); 

कौन सा इनमें से, या संभवतः कुछ, संभावित रूप से NULL सूचक से std::string आरंभ करने का सबसे अच्छा या सबसे उचित तरीका है, और क्यों? क्या यह विभिन्न सी ++ मानकों के लिए अलग है? सामान्य रिलीज बिल्ड अनुकूलन झंडे मान लें।

मैं एक सही तरीका है, या एक संदर्भ लिंक के साथ एक उत्तर के स्पष्टीकरण के साथ एक उत्तर की तलाश कर रहा हूं (यह भी लागू होता है अगर उत्तर "कोई फर्क नहीं पड़ता"), न केवल व्यक्तिगत राय (लेकिन यदि आपको अवश्य ही कम से कम एक टिप्पणी करना है)।

+0

यह सब उस पर निर्भर करता है कि आप एक नलप्टर का मतलब क्या चाहते हैं। क्या यह आपके लिए खाली स्ट्रिंग जैसा ही है, या इसका अलग अर्थ होना चाहिए? – PlasmaHH

+0

मुझे लगता है कि आपको पहले विकल्प का उपयोग करना चाहिए क्योंकि आप केवल एक बार स्ट्रिंग के कन्स्ट्रक्टर को कॉल करते हैं। – Alexis

+1

@PlasmaHH ठीक है, मैं चाहता हूं कि कोड स्निपेट क्या करे, जब चार सूचक न्यूल हो। – hyde

उत्तर

15

अंतिम व्यक्ति मूर्खतापूर्ण है क्योंकि यह प्रारंभ होने पर प्रारंभिकरण का उपयोग नहीं करता है।

पहले दो पूरी तरह से समान रूप से समान हैं (c_str() सदस्य फ़ंक्शन के बारे में सोचें), इसलिए पहले संस्करण को प्राथमिकता दें क्योंकि यह सबसे प्रत्यक्ष और बेवकूफ है, और पढ़ने के लिए सबसे आसान है।

(वहाँ एक अर्थ अंतर अगर std::string एक constexpr डिफ़ॉल्ट निर्माता था हो सकता है, लेकिन यह नहीं है। फिर भी, यह संभव है कि std::string()std::string("") से अलग है, लेकिन मैं किसी भी कार्यान्वयन करना है कि पता नहीं है यही नहीं, यह भावना का एक बहुत बनाने के लिए लग रहे हैं के बाद से नहीं है। दूसरी ओर, लोकप्रिय छोटे स्ट्रिंग अनुकूलन आजकल मतलब है कि दोनों संस्करणों शायद नहीं किसी भी गतिशील आवंटन प्रदर्शन करेंगे।)


अद्यतन: @Jonathan बताते हैं के रूप में, दो स्ट्रिंग कंस्ट्रक्टर्स शायद अलग कोड निष्पादित होगा, और है कि अगर आप के लिए मायने रखती है (हालांकि यह वास्तव में नहीं होना चाहिए), तो आप एक चौथे संस्करण की सोच सकते हैं:

: cstr ? cstr : std::string() 

दोनों पठनीय और डिफ़ॉल्ट निर्माण।


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


गिगल्स के लिए, मैं बजना 3 के माध्यम से दोनों संस्करणों को चलाने गए हैं।3, -O3, x86_64 पर, एक struct foo; तुम्हारा और एक समारोह foo bar(char const * p) { return p; } तरह के लिए के साथ:

डिफ़ॉल्ट निर्माता (std::string()):

.cfi_offset r14, -16 
    mov  R14, RSI 
    mov  RBX, RDI 
    test R14, R14 
    je  .LBB0_2 
    mov  RDI, R14 
    call strlen 
    mov  RDI, RBX 
    mov  RSI, R14 
    mov  RDX, RAX 
    call _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcm 
    jmp  .LBB0_3 
.LBB0_2: 
    xorps XMM0, XMM0 
    movups XMMWORD PTR [RBX], XMM0 
    mov  QWORD PTR [RBX + 16], 0 
.LBB0_3: 
    mov  RAX, RBX 
    add  RSP, 8 
    pop  RBX 
    pop  R14 
    ret 

खाली स्ट्रिंग निर्माता (""):

.cfi_offset r14, -16 
    mov  R14, RDI 
    mov  EBX, .L.str 
    test RSI, RSI 
    cmovne RBX, RSI 
    mov  RDI, RBX 
    call strlen 
    mov  RDI, R14 
    mov  RSI, RBX 
    mov  RDX, RAX 
    call _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcm 
    mov  RAX, R14 
    add  RSP, 8 
    pop  RBX 
    pop  R14 
    ret 

.L.str: 
    .zero 1 
    .size .L.str, 1 

मेरे मामले में, यह भी दिखाई देगा कि ""बेहतर कोड उत्पन्न करता है: दोनों संस्करण strlen पर कॉल करते हैं, लेकिन खाली-स्ट्रिंग संस्करण किसी भी कूद का उपयोग नहीं करता है, केवल सशर्त चाल (क्योंकि उसी कन्स्ट्रक्टर को केवल दो अलग-अलग तर्कों के साथ कहा जाता है)। बेशक यह एक पूरी तरह से अर्थहीन, गैर-पोर्टेबल और गैर-हस्तांतरणीय अवलोकन है, लेकिन यह दिखाता है कि संकलक को हमेशा जितनी मदद हो सकती है उतनी मदद की आवश्यकता नहीं होती है। बस सबसे अच्छा दिखने वाला कोड लिखें।

+2

पहले दो समान नहीं हैं, यहां तक ​​कि आईएमएचओ भी अर्थात्, उनमें से एक में 'strlen' के लिए एक कॉल है, जिसे संकलक शायद संकलन-समय पर प्रतिस्थापित कर सकता है, लेकिन आप अभी भी 'std :: string के लिए अलग-अलग कोड पथ कहते हैं () 'और' std :: स्ट्रिंग ("", 0) '। चूंकि आप जानते हैं कि सामग्री खाली कॉलिंग है, डिफॉल्ट कन्स्ट्रक्टर गुजरने, गणना करने और शून्य-लंबाई 'चार' सरणी –

+0

की प्रतिलिपि बनाने से अधिक समझ में आता है, ठीक है, कुछ व्यापक रूप से उपयोग किए गए सी ++ स्ट्रिंग क्लासेस (कम से कम क्यूटी' क्यूस्ट्रिंग') " नल स्ट्रिंग "खाली स्ट्रिंग" से अलग है, जो प्रेरणा का हिस्सा है मैंने इस सवाल से क्यों पूछा। – hyde

+3

@ जोनाथन वाकई: दाएं, कोड में समान नहीं है, लेकिन अर्थात् ... (और एक खाली स्ट्रिंग पर 'strlen' अभी भी बहुत अच्छा है)। अरे, 'cstr के बारे में क्या? cstr: स्ट्रिंग() '? –

1

मान लें कि आप cstr == NULL से खुश हैं mStdString खाली, मुझे लगता है कि पहला सबसे अच्छा शायद सबसे अच्छा है।

यदि कुछ और नहीं है, तो आपके द्वारा प्रदान किया जाने वाला तीसरा विकल्प काम नहीं करता है अगर mStdStringconst है। मध्यम विकल्प सी ++ 11 के तहत "चाल semantics" से लाभ, लेकिन कम स्पष्ट रूप से इष्टतम या उचित है।

तो, मेरा वोट पहले विकल्प के साथ चला जाता है।

+0

"उचित अनुकूलन मानना" हम शायद मान सकते हैं कि कोई वास्तविक चाल की आवश्यकता नहीं है और कोई प्रतियां elided हैं। –

1

पहली बात पहले, तुम सही हो, http://www.cplusplus.com/reference/string/string/string/ से:

रों एक अशक्त सूचक है, तो अगर n == एनपीओ, या अगर सीमा के आधार पर [प्रथम, अंतिम) निर्दिष्ट मान्य नहीं है, यह अपरिभाषित व्यवहार का कारण बनता है।

इसके अलावा, यह आपके लिए एक नल पॉइंटर का अर्थ है इस पर निर्भर करता है। मैं इसे आपके लिए एक खाली स्ट्रिंग से भी मानता हूं।

मैं पहले के साथ जाऊंगा, क्योंकि यह मैंने सबसे अच्छा पढ़ा है। पहला समाधान और दूसरा वही हैं। यदि आपकी स्ट्रिंग const थी तो तीसरा काम नहीं करेगा।

0

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

क्यों प्रारंभ शून्य हो char * होगा - और यदि हां, तो आप फोन करने वाले के लिए यह धक्का नहीं कर सकता है कि स्थिति से कुछ समझ बनाने के लिए - जैसे कोई रिक्त स्ट्रिंग गुजर, या "unknown" या "(null)" के रूप में के रूप में उपयुक्त।

दूसरे शब्दों में, कुछ इस तरह:

void MyClass::MyClass(const char *cstr) 
{ 
    assert(cstr != NULL); // or "throw cstr_must_not_be_null;" or some such. 
    mStdString = cstr; 
} 

(संभवतः एक प्रारंभकर्ता सूची में यह करने के लिए कुछ चतुर तरीका है, लेकिन मैं कैसे सही ढंग से करने के लिए यह पता लगाने की परवाह नहीं जा सकता है) ।

मैं किसी के लिए "यह वास्तव में मौजूद नहीं है" की तुलना में स्ट्रिंग पैरामीटर के इनपुट के रूप में न्यूल पर उत्सुक नहीं है - और यदि आप वास्तव में दोहराने की कोशिश कर रहे हैं, तो आपके पास boolean होना चाहिए कहने के लिए "मौजूद नहीं है", या std::string पर पॉइंटर जो शून्य नहीं हो सकता है यदि कोई स्ट्रिंग मौजूद नहीं है।

+0

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

+0

मैंने वर्चुअल सदस्य फ़ंक्शन कहा, लेकिन कृपया "वर्चुअल" को क्षमा करें। मैं एक ही कक्षा पदानुक्रम में एक कन्स्ट्रक्टर के अंदर से वर्चुअल फ़ंक्शन को कॉल करने के प्रभावों को समझता हूं। मेरी टिप्पणी के प्रयोजनों के लिए, गैर वर्चुअल सदस्य फ़ंक्शन पर्याप्त हैं। –

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