2009-12-31 5 views
31

मैं निम्नलिखित की तरह कुछ रखरखाव के काम कर रहा हूँ और भाग गया कुछ भर में:क्या "& s [0]" std :: स्ट्रिंग में संगत वर्णों को इंगित करता है?

std::string s; 
s.resize(strLength); 
// strLength is a size_t with the length of a C string in it. 

memcpy(&s[0], str, strLength); 

मैं & s का उपयोग करके [0] सुरक्षित अगर यह एक std :: वेक्टर था होगा पता है, लेकिन यह एक सुरक्षित उपयोग है std :: स्ट्रिंग का?

+3

एस [0] का उपयोग ठीक है, memcpy() तर्कसंगत रूप से कम है। क्यों न केवल असाइनमेंट करें, या स्ट्रिंग के असाइन() सदस्य फ़ंक्शन का उपयोग करें? –

+1

@ नील बटरवर्थ, यही वह है जो मैं इस कोड को देखते हुए खुद से पूछ रहा हूं ...;) – paxos1977

+0

जब आप सी ++ में अनुभव प्रोग्रामिंग प्राप्त करते हैं, तो आप 'memset' और' memcpy' का उपयोग करने से अधिक से अधिक बचना होगा, और सीखेंगे तर्क यह आपके अनुभव में जोड़ने वाला है। –

उत्तर

34

एक std :: स्ट्रिंग का आवंटन C++ 98/03 मानक के तहत संगत होने की गारंटी नहीं है, लेकिन सी ++ 11 इसे बल देता है। अभ्यास में, न तो मैं और न ही Herb Sutter एक कार्यान्वयन के बारे में जानता हूं जो संगत भंडारण का उपयोग नहीं करता है।

ध्यान दें कि &s[0] चीज हमेशा 0-लंबाई स्ट्रिंग मामले में सी ++ 11 मानक द्वारा काम करने की गारंटी दी जाती है। यह गारंटी नहीं किया जा अगर आप str.begin() या &*str.begin() किया था, लेकिन &s[0] के लिए मानक operator[] के रूप में परिभाषित करता है:

रिटर्न:, *(begin() + pos) अगर pos < size() मूल्य charT() साथ प्रकार T का एक उद्देश्य के लिए अन्यथा एक संदर्भ; [0,size()] में प्रत्येक i के लिए एक संकेतक p ऐसी है कि p + i == &operator[](i): संदर्भित मूल्य

संशोधित करेगा नहीं किया जा पर जारी रखते हुए, data() के रूप में परिभाषित किया गया है:

रिटर्न।


सूचना (सीमा के दोनों सिरों पर वर्ग कोष्ठक नोटिस): पूर्व मानकीकरण C++ 0x &s[0] की गारंटी नहीं था शून्य लंबाई तार के साथ काम करने (वास्तव में, यह स्पष्ट रूप से अपरिभाषित व्यवहार था), और इस उत्तर के पुराने संशोधन ने इसे समझाया; इसे बाद के मानक ड्राफ्ट में तय किया गया है, इसलिए उत्तर तदनुसार अपडेट किया गया है।

+0

मैं पिछले कुछ महीनों के लिए मानक का पालन नहीं कर रहा हूं, लेकिन यह मेरी धारणा थी कि यह अभी भी 0x ड्राफ्ट में था, और वास्तव में अभी तक आवश्यक नहीं है (या यदि पुस्तकालय केवल '03 लागू करने का विकल्प चुनता है)। –

+3

सटर उस पोस्ट पर एक टिप्पणी में कहता है, "मौजूदा आईएसओ सी ++ को स्ट्रिंग डेटा (लेकिन जरूरी नहीं कि निरंतर समाप्त हो गया है) के लिए एक सूचक को खांसी के लिए आवश्यक है [0]," जो वास्तव में ओपी के उपयोग को सही बना देगा। हालांकि, मुझे कुछ भी नहीं मिला जो कहता है कि मानक में (कम से कम यह 21.3.4 lib.string.access में नहीं है)। –

+0

मुझे लगता है कि यह सही हो सकता है; एसडीडी दोष 530 कहता है ऑपरेटर [] संगत है लेकिन इटरेटर इंटरफेस की गारंटी नहीं है, और 23.4.4 उद्धरण। मैं जांच करने के लिए अपने मानक खोद रहा हूँ। –

6

तकनीकी रूप से, नहीं, std::string से इसकी सामग्री को स्मृति में संगत रूप से संग्रहीत करने की आवश्यकता नहीं है।

हालांकि, लगभग सभी कार्यान्वयन (जिनमें से प्रत्येक कार्यान्वयन मुझे पता है) में, सामग्री को व्यवस्थित रूप से संग्रहीत किया जाता है और यह "काम करेगा।"

+0

क्या आप कुछ कार्यान्वयन की पहचान कर सकते हैं जहां यह काम नहीं करेगा? –

+2

नहीं। लेकिन अगर आप चाहें तो ऐसा कार्यान्वयन कर सकते हैं। –

+0

@Neil: क्या आपके पास उस टीसी का लिंक/संदर्भ है? –

2

पाठकों को ध्यान रखना चाहिए कि 200 9 में यह सवाल पूछा गया था, जब सी ++ 03 मानक वर्तमान प्रकाशन था। यह उत्तर मानक के उस संस्करण पर आधारित है, जिसमें std::string एस संगत संग्रहण का उपयोग करने की गारंटी नहीं है। चूंकि इस सवाल को किसी विशेष प्लेटफ़ॉर्म (जैसे जीसीसी) के संदर्भ में नहीं पूछा गया था, इसलिए मैं ओपी के प्लेटफ़ॉर्म के बारे में कोई धारणा नहीं करता - विशेष रूप से, मौसम या string के लिए यह प्रतिष्ठित संग्रहण का उपयोग नहीं करता है।

कानूनी? शायद शायद नहीं। सुरक्षित? शायद, लेकिन शायद नहीं। अच्छा कोड? खैर, चलो वहाँ नहीं जाते ...

क्यों न सिर्फ कार्य करें:

std::string s = str; 

... या:

std::string s(str); 

... या:

std::string s; 
std::copy(&str[0], &str[strLen], std::back_inserter(s)); 

... या:

std::string s; 
s.assign(str, strLen); 

?

+0

या s.assign (str, strLen); –

+0

अच्छा, अद्यतन w/असाइन करें –

+1

'std :: string s (str, strLen);' (एम्बेडेड नल के मामले में, सबसे कम फॉर्म समान, प्रश्न के मूल व्यवहार के लिए, शून्य से समाप्त होने की कमी के मामले में।) –

0

यह आम तौर पर सुरक्षित है, भले ही आंतरिक स्ट्रिंग अनुक्रम लगातार स्मृति में संग्रहीत किया गया हो या नहीं। निरंतरता के अलावा std::string ऑब्जेक्ट द्वारा नियंत्रित अनुक्रम को संग्रहीत करने के तरीके से संबंधित कई अन्य कार्यान्वयन विवरण हो सकते हैं।

इसके साथ वास्तविक व्यावहारिक समस्या निम्न हो सकती है। std::string के नियंत्रित अनुक्रम को शून्य-समाप्त स्ट्रिंग के रूप में संग्रहीत करने की आवश्यकता नहीं है। हालांकि, व्यावहारिक रूप से, कई (अधिकांश?) कार्यान्वयन आंतरिक बफर को 1 से अधिक करने का चयन करते हैं और अनुक्रम को शून्य-समाप्त स्ट्रिंग के रूप में संग्रहीत करते हैं क्योंकि यह c_str() विधि के कार्यान्वयन को सरल बनाता है: केवल आंतरिक बफर पर एक पॉइंटर लौटाएं और आप किया हुआ।

आपके प्रश्न में उद्धृत कोड आंतरिक बफर में कॉपी किए गए डेटा को शून्य-समाप्त करने का कोई प्रयास नहीं करता है। काफी संभवतः यह नहीं जानता कि std::string के कार्यान्वयन में शून्य-समाप्ति आवश्यक है या नहीं। काफी संभवतः यह resize पर कॉल के बाद ज़ीरो से भरे आंतरिक बफर पर निर्भर करता है, इसलिए कार्यान्वयन द्वारा शून्य टर्मिनेटर के लिए आवंटित अतिरिक्त वर्ण आसानी से शून्य पर पूर्व-निर्धारित होता है। यह सब कार्यान्वयन विस्तार है, जिसका अर्थ यह है कि यह तकनीक कुछ नाजुक धारणाओं पर निर्भर करती है।

दूसरे शब्दों में, आपको कुछ कार्यान्वयन में शायद strcpy का उपयोग करना होगा, memcpy डेटा को नियंत्रित अनुक्रम में डेटा को मजबूर करने के लिए। जबकि कुछ अन्य कार्यान्वयन में आपको memcpy और strcpy का उपयोग करना होगा।

+1

'आकार बदलने' के लिए कॉल के बाद आप पूरी तरह से सुनिश्चित हो सकते हैं कि आंतरिक स्ट्रिंग को कार्यान्वयन की आवश्यकता के रूप में शून्य-समाप्त नहीं किया गया है या नहीं। 'आकार बदलने' के लिए कॉल करने के बाद आपके पास एन अक्षरों की वैध स्ट्रिंग होनी चाहिए (आवश्यकतानुसार शून्य वर्णों के साथ गद्देदार)। - हालांकि, यह 'std :: string' वर्ग के लिए समझ की कमी दिखाता है: memcpy या तो अज्ञानता से या प्रदर्शन के लिए एक गुमराह प्रयास के रूप में उपयोग किया जाता है ('आकार बदलने' के कारण कोड को बफर को मान निर्दिष्ट करने के लिए समाप्त होता है दो बार)। – UncleBens

+0

@UncleBens: मैं आपकी पहली वाक्य को समझ नहीं पा रहा हूं। किसी भी मामले में, हाँ, भाषा मानक गारंटी देता है कि आकार बढ़ने 'आकार बदलने' कॉल शून्य के साथ स्ट्रिंग पैड करता है। हालांकि, मानक अनुरोधित आकार (केवल इस मामले में 'strLength') तक पैडिंग की गारंटी देता है, लेकिन कार्यान्वयन को उस आवंटित करने के लिए मानक में कोई गारंटी नहीं है, यदि कार्यान्वयन एक आवंटित करता है। – AnT

0

कोड काम कर सकता है, लेकिन निर्णय से भाग्य से अधिक, यह उस कार्यान्वयन के बारे में धारणा करता है जो गारंटी नहीं है। मैं निर्धारित करने का सुझाव देते हैं कोड की वैधता अप्रासंगिक है, जबकि यह जटिलता पर एक व्यर्थ है कि आसानी से बस करने के लिए कम है:

std::string s(str) ; 

या यदि एक मौजूदा std :: स्ट्रिंग वस्तु को बताए, बस:

s = str ; 

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

+0

मैं वास्तव में यह सुनिश्चित नहीं कर सकता कि स्ट्रिंग को आवंटित किया जा रहा है। तो सबसे अच्छा मैं कर सकता था शायद s.assign (पीआरटी, ptrLength) होगा; जो अभी भी एक सुधार है मुझे लगता है। – paxos1977

+0

कन्स्ट्रक्टर फॉर्म का उपयोग करें: 'std :: string s (str, strLen);' – GManNickG

6

यह उपयोग करने के लिए सुरक्षित है। मुझे लगता है कि ज्यादातर जवाब एक बार सही थे, लेकिन मानक बदल गया। सी ++ 11 मानक से हवाला देते हुए, सामान्य आवश्यकताओं basic_string [string.require], 21.4.1.5, कहते हैं: एक basic_string वस्तु में

चार-तरह की वस्तुओं समीपवर्ती संग्रहीत किया जाएगा।यही कारण है कि किसी भी basic_string वस्तु ओं के लिए, है, पहचान & * (s.begin() + n) == & * s.begin() + n इस तरह के एन के सभी मानों कि 0 < = n < रों के लिए पकड़ जाएगा .size()।

इससे पहले थोड़ा, यह कहता है कि सभी इटेटरेटर यादृच्छिक एक्सेस इटरेटर हैं। दोनों बिट्स आपके प्रश्न के उपयोग का समर्थन करते हैं। (इसके अतिरिक्त, स्ट्रॉस्ट्रप स्पष्ट रूप से अपनी नवीनतम पुस्तक में इसका उपयोग करता है;))

यह परिवर्तन संभव नहीं है कि यह परिवर्तन सी ++ 11 में किया गया हो। मुझे याद है कि वेक्टर के लिए वही गारंटी जोड़ा गया था, जिसे उस रिलीज के साथ बहुत उपयोगी डेटा() पॉइंटर भी मिला।

उम्मीद है कि मदद करता है।

+2

प्रश्न प्री-सी ++ 11 था (इसे इस तरह टैग किया गया है)। आप सही हैं, सी ++ 11 ने इसे करने के लिए आधिकारिक रूप से सुरक्षित बना दिया है। – paxos1977

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