2016-05-06 8 views
22

इस तरह एक कोड को ध्यान में रखते:क्या यह std :: स्ट्रिंग को स्वयं में जोड़ना सुरक्षित है?

std::string str = "abcdef"; 
const size_t num = 50; 

const size_t baselen = str.length(); 
while (str.length() < num) 
    str.append(str, 0, baselen); 

इसे इस तरह खुद पर std::basic_string<T>::append() कॉल करने के लिए सुरक्षित है? कॉपी ऑपरेशन से पहले बढ़कर स्रोत मेमोरी को अमान्य कर दिया जा सकता है?

मुझे उस विधि के विशिष्ट मानक में कुछ भी नहीं मिला। यह कहता है कि उपर्युक्त str.append(str.data(), baselen) के बराबर है, जो मुझे लगता है कि append(const char*, size_t) के अंदर ऐसे मामलों का एक और पता लगाने तक मुझे पूरी तरह से सुरक्षित नहीं किया जा सकता है।

मैंने कुछ कार्यान्वयन की जांच की और वे सुरक्षित तरीके से एक या दूसरे लग रहे थे, लेकिन मेरा सवाल यह है कि यदि इस व्यवहार की गारंटी है। जैसे "Appending std::vector to itself, undefined behavior?" कहता है कि यह std::vector के लिए नहीं है।

+0

यह होना चाहिए लेकिन खुद की तरह मुझे कुछ भी रास्ता नहीं मिल सकता है। 'str + = str; 'कानूनी है और यह एक ही चीज़ पर उबालता है इसलिए मुझे लगता है कि यह ठीक है। – NathanOliver

+0

@NathanOliver: वास्तव में, इसे अवैध बनाने के लिए एक अच्छा कारण नहीं है। तारों के साथ, एक ही स्ट्रिंग को स्वयं को जोड़ना, या स्ट्रिंग का सबसेट, उचित है। 'वेक्टर' के साथ, यह बहुत कम संभावना है। –

+0

@ निकोलबोलस मुझे वह मिलता है। मैं बस अपने तर्क का समर्थन करने के लिए मानक नहीं ढूंढ रहा था। ऐसा लगता है जैसे Rakete1111 किया था। – NathanOliver

उत्तर

15

अनुसार §21.4.6.2/§21.4.6.3 रहे हैं:

समारोह [basic_string& append(const charT* s, size_type n);] स्ट्रिंग लंबाई आकार के एक स्ट्रिंग (के साथ * द्वारा इस नियंत्रित बदल देता है) + n जिनकी पहली आकार () तत्व * द्वारा नियंत्रित मूल स्ट्रिंग की एक प्रति हैं और जिनके शेष तत्व एस के शुरुआती एन तत्वों की एक प्रति हैं।

नोट: यह हर append कॉल करने के लिए, के रूप में मानक द्वारा परिभाषित लागू होता है के रूप में हर appendappend(const charT*, size_type) के मामले में लागू किया जा सकता, (§21.4.6.2/§21.4.6.3)।

तो बुनियादी तौर पर, append, str की एक प्रति (प्रतिलिपि strtemp कॉल) बना देता है strtemp को str2 की n पात्रों जोड़ देती है, और उसके बाद strtemp साथ str बदल देता है।

str2strstr है, कुछ भी नहीं बदलता है, क्योंकि स्ट्रिंग को बढ़ाया जाता है जब अस्थायी प्रतिलिपि असाइन की जाती है, पहले नहीं।

हालांकि यह मानक में स्पष्ट रूप से नहीं बताया गया है, भले ही std::basic_string<T>::append की परिभाषा द्वारा यह गारंटी दी जाती है (यदि कार्यान्वयन मानक में बिल्कुल बताया गया है)।

इस प्रकार, यह अपरिभाषित व्यवहार नहीं है।

+0

मुझे लगता है, धन्यवाद - मुझे 'एपेंड (कॉन्स chart *, size_type)' की परिभाषा को और अधिक सचमुच पढ़ना चाहिए था। – Yirkha

6

यह जटिल है।

एक चीज जिसे निश्चित रूप से कहा जा सकता है। आप iterators का उपयोग करते हैं:

std::string str = "abcdef"; 
str.append(str.begin(), str.end()); 

तो आप गारंटी सुरक्षित रहने के लिए कर रहे हैं। हाँ सच। क्यूं कर? क्योंकि विनिर्देश बताता है कि इटरेटर फ़ंक्शन का व्यवहार append(basic_string(first, last)) पर कॉल करने के बराबर है। यह स्पष्ट रूप से स्ट्रिंग की एक अस्थायी प्रति बनाता है। इसलिए यदि आपको स्वयं में एक स्ट्रिंग डालने की आवश्यकता है, तो आप इसे इटरेटर फॉर्म के साथ करने में सक्षम होने की गारंटी देते हैं।

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

append के सभी अन्य रूपों को append(const charT *s, size_t len) पर कॉल करने के बराबर समझा जाता है। यही है, उपरोक्त संलग्न करने के लिए आपकी कॉल append(str.data(), str.size()) करने के बराबर है। तो s*this के अंदर क्या होता है तो मानक क्या होता है?

कुछ भी नहीं।

s का केवल आवश्यकता है: charT के कम से कम n तत्वों की एक सरणी के लिए

s अंक।

चूंकि यह *this में स्पष्ट रूप से न करे s ओर इशारा करते हुए करता है, तो यह अनुमति दी जानी चाहिए। अगर इटरेटर संस्करण स्वयं-असाइनमेंट की अनुमति देता है तो यह बहुत अजीब होगा, लेकिन सूचक & आकार संस्करण नहीं था।

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