क्या `string.assign (string.data (), 5)` अच्छी तरह से परिभाषित या UB है?


11

एक सहकर्मी यह लिखना चाहता था:

std::string_view strip_whitespace(std::string_view sv);

std::string line = "hello  ";
line = strip_whitespace(line);

मैंने कहा कि वापसी string_viewने मुझे एक प्राथमिकता दी है , और इसके अलावा, यहाँ अलियासिंग मुझे यूबी की तरह लग रहा था।

मैं निश्चितता के साथ कह सकता हूं कि line = strip_whitespace(line)इस मामले में बराबर है line = std::string_view(line.data(), 5)। मुझे विश्वास है कि वह कॉल करेगा string::operator=(const T&) [with T=string_view], जिसे इसके बराबर परिभाषित किया गया है line.assign(const T&) [with T=string_view], जिसे इसके समकक्ष परिभाषित किया गया है line.assign(line.data(), 5), जिसे ऐसा करने के लिए परिभाषित किया गया है:

Preconditions: [s, s + n) is a valid range.
Effects: Replaces the string controlled by *this with a copy of the range [s, s + n).
Returns: *this.

लेकिन जब अलियासिंग होता है तो यह नहीं कहता है।

मैंने कल कप्पलंग स्लैक पर यह प्रश्न पूछा और मिश्रित उत्तर मिले। सुपर आधिकारिक जवाबों की तलाश में, और / या वास्तविक पुस्तकालय विक्रेताओं के कार्यान्वयन का अनुभवजन्य विश्लेषण।


मैं परीक्षण मामलों लिखा था के लिए string::assign, vector::assign, deque::assign, list::assign, और forward_list::assign

  • Libc ++ इन सभी परीक्षण मामलों को काम करता है।
  • Libstdc ++ उन सभी को छोड़कर काम करता है forward_list, जो segfaults करते हैं।
  • मैं MSVC के पुस्तकालय के बारे में नहीं जानता।

Libstdc ++ में सीगफॉल्ट मुझे आशा देता है कि यह यूबी है; लेकिन मैं यह भी देखता हूं कि दोनों libc ++ और libstdc ++ इस काम को कम से कम आम मामलों में करने के लिए बहुत प्रयास कर रहे हैं।


क्या आपने आसन के साथ परीक्षण के मामलों को संकलित किया और / या उन्हें वेलग्रिंड के तहत चलाया? यह अनुमान लगा लेता है कि क्या कोड पहुंच उल्लंघन का कारण बनता है, हालांकि यह परिभाषा के बजाय व्यवहार में अभी भी काम कर सकता है।
कोनराड रुडोल्फ

1
"यदि कोई भी सदस्य फ़ंक्शन या basic_string का ऑपरेटर अपवाद को फेंकता है, तो उस फ़ंक्शन या ऑपरेटर का आधारभूत ऑब्जेक्ट पर कोई अन्य प्रभाव नहीं होता है।" - यह भंडारण के आवंटन को मौजूदा भंडारण से पहले होने से मुक्त कर देता है, ताकि यदि कोई बदलाव किए बिना आवंटन विफल हो जाता है, तो एक अपवाद हो जाता है *this। लेकिन मुझे लगता है कि मौजूदा स्टोरेज को दोबारा इस्तेमाल होने से रोकने के लिए कुछ भी नहीं है, इस स्थिति में यह अनिर्दिष्ट हो जाता है, क्योंकि स्टोरेज को कॉपी-ओवर करने का शब्दार्थ अनिर्दिष्ट है।
सैम वार्शविक


2
अनुक्रम उल्लेख कंटेनरों के लिए, यह निश्चित रूप से यूबी की पूर्व शर्त उल्लंघन की वजह से है, assignमें आवश्यकताओं [: container.seq.req टैब]
अखरोट

जवाबों:


8

अपवाद के एक जोड़े जिनमें से तुम्हारा एक नहीं है को छोड़कर, एक गैर स्थिरांक सदस्य समारोह (यानी बुला assignएक स्ट्रिंग पर) को अमान्य कर [...] संकेत [...] उसके तत्वों के लिए। इस का उल्लंघन करती है पूर्व शर्त पर assignकि [s, s + n)किसी मान्य श्रेणी है, इसलिए इस अपरिभाषित व्यवहार है।

ध्यान दें कि string::operator=(string const&)विशेष रूप से स्व-असाइनमेंट को नो-ऑप बनाने के लिए भाषा है।


1
तो वास्तव में अमान्य होने का बिंदु क्या है और जिस बिंदु पर होल्ड करने के लिए पूर्व शर्त की आवश्यकता है? उत्तर यह मानकर चल रहा है कि सदस्य फ़ंक्शन को बुलाए जाने के बाद पूर्व शर्त को पकड़ना चाहिए।
अखरोट

1
@walnut मैं कोई भाषा-वकील नहीं हूं (न ही विशेष रूप से विस्तारित C ​​++ ज्ञान वाला व्यक्ति), लेकिन जब हम आपके परिदृश्य को उलट देते हैं, तो हम एक सवाल पूछ सकते हैं - क्या फांसी के दौरान सीमा को अमान्य किया जा सकता है assign? यदि हाँ, तो हमें असाइनमेंट के कार्यान्वयन के अंदर एक विशिष्ट बिंदु निर्धारित करना होगा जब वास्तव में अमान्य हो सकता है, और मुझे विश्वास है कि सी ++ कुछ ऐसा नहीं करेगा। मुझसे गलती भी हो सकती है।
फ्यूरिश

2
@Fureeish मैं या तो नहीं जानता, लेकिन उदाहरण के लिए LWG 526 अंक को देखें , जिसे " दोष नहीं " के रूप में बंद किया गया है , जिसमें बंद करने के लिए अपनी सिफारिश में उल्लेख किया गया है कि std::vector::insert(iterator pos, const T& value)अगर valueवेक्टर में ही काम करना होगा , तो मानक इसे निर्दिष्ट नहीं करता है काम करने की अनुमति नहीं है, भले ही उस संदर्भ को कॉल द्वारा अमान्य किया जा सकता है।
अखरोट

1
@walnut " को काम करने की आवश्यकता है क्योंकि मानक इसके लिए काम नहीं करने की अनुमति नहीं देता है। " - इसे प्यार करें । सू ... क्या यह पूछने योग्य है कि व्यवहार में क्या होता है ? क्या ऐसी स्थिति में तर्क की प्रति बनाने के लिए कार्यान्वयन की आवश्यकता है? आप इसे वास्तविक रूप से कैसे लागू कर सकते हैं ..? मैंने मानक के बारे में सुना है कि असंभव को पूरा करने के लिए संकलक की आवश्यकता है - क्या यह उन मामलों में से एक है? भले ही, आप टिप्पणी के लिए धन्यवाद!
फ्यूरिश

1
@Fureeish वास्तव में मेरा पिछला (अब हटा दिया गया) उदाहरण वास्तव में परीक्षण नहीं कर रहा था कि मैं क्या परीक्षण करना चाहता था। यहां एक निश्चित उदाहरण दिखाया गया है कि दोनों libc ++ और libstdc ++ वास्तव में आवश्यकता के अनुसार वास्तविककरण पर जाने से पहले कॉपी करते हैं।
अखरोट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.