मुझे एक इंटरफ़ेस में string_view का उपयोग कब करना चाहिए?


16

मैं एक आंतरिक पुस्तकालय का उपयोग कर रहा हूं जिसे एक प्रस्तावित C ++ पुस्तकालय की नकल करने के लिए डिज़ाइन किया गया था , और पिछले कुछ वर्षों में मुझे इसका इंटरफ़ेस उपयोग std::stringकरने से बदल गया है string_view

इसलिए मैं नए इंटरफ़ेस के अनुरूप अपने कोड को कर्तव्यपूर्वक बदल देता हूं। दुर्भाग्य से, मुझे जो पास करना है वह एक std :: string पैरामीटर, और कुछ ऐसा है जो std :: string return value है। तो मेरा कोड कुछ इस तरह से बदल गया:

void one_time_setup(const std::string & p1, int p2) {
   api_class api;
   api.setup (p1, special_number_to_string(p2));
}

सेवा

void one_time_setup(const std::string & p1, int p2) {
   api_class api;
   const std::string p2_storage(special_number_to_string(p2));
   api.setup (string_view(&p1[0], p1.size()), string_view(&p2_storage[0], p2_storage.size()));
}

मैं वास्तव में यह नहीं देखता कि इस बदलाव ने मुझे API क्लाइंट के रूप में खरीदा, जो कि अधिक कोड (संभवतः स्क्रू अप करने के लिए) के अलावा था। एपीआई कॉल कम सुरक्षित है (एपीआई अब अपने मापदंडों के लिए भंडारण के मालिक नहीं होने के कारण), संभवत: मेरे कार्यक्रम 0 कार्य को सहेजा गया (चालें अनुकूलन के कारण कंपाइलर अब कर सकते हैं), और यहां तक ​​कि अगर यह काम नहीं बचा, तो यह केवल होगा आवंटन का एक जोड़ा है जो स्टार्टअप के बाद या कहीं बड़े लूप में नहीं होगा और न ही होगा। इस एपीआई के लिए नहीं।

हालाँकि, यह दृष्टिकोण मुझे कहीं और देखने की सलाह का पालन करता है, उदाहरण के लिए यह उत्तर :

एक तरफ के रूप में, C ++ 17 के बाद से आपको एक const std पास करने से बचना चाहिए :: string & a std के पक्ष में :: string_view:

मुझे वह सलाह आश्चर्यजनक लगी, क्योंकि यह मुख्य रूप से अनुकूलन के प्रयोजनों के लिए कम सुरक्षित एक (मूल रूप से महिमा सूचक और लंबाई) के साथ एक अपेक्षाकृत सुरक्षित वस्तु की जगह सार्वभौमिक रूप से प्रतिस्थापित करने की वकालत करता प्रतीत होता है।

तो जब चाहिए string_view इस्तेमाल किया जा, और जब यह नहीं करना चाहिए?


1
आपको कभी भी std::string_viewकंस्ट्रक्टर को सीधे कॉल नहीं करना चाहिए , आपको स्ट्रिंग्स को std::string_viewसीधे लेने की विधि को पास करना चाहिए और यह स्वचालित रूप से परिवर्तित हो जाएगा।
मटिज़

@ मगज़ - हम्म। मैं एक पूर्ण विकसित C ++ 17 संकलक का उपयोग नहीं कर रहा हूं (अभी तक), इसलिए शायद यह मुद्दा है। फिर भी, यहाँ नमूना कोड इसकी आवश्यकता को इंगित करता था, कम से कम एक की घोषणा करते समय।
TED

4
मेरा उत्तर देखें रूपांतरण ऑपरेटर <string>हेडर में है और स्वचालित रूप से होता है। वह कोड धोखा और गलत है।
मटिज़

1
"कम सुरक्षित वाले के साथ" एक स्लाइस एक स्ट्रिंग संदर्भ से कम सुरक्षित कैसे है?
कोडइन्चोस

3
@TED ​​कॉलर आसानी से आपके संदर्भ को इंगित करने वाले स्ट्रिंग को आसानी से मुक्त कर सकता है क्योंकि वे उस मेमोरी को मुक्त कर सकते हैं जो टुकड़ा इंगित कर रहा है।
कोडइन्चोस

जवाबों:


18
  1. क्या मूल्य लेने वाली कार्यक्षमता को स्ट्रिंग का स्वामित्व लेने की आवश्यकता है? यदि ऐसा है तो std::string(नॉन-कास्ट, नॉन-रेफ)। यह विकल्प आपको एक मूल्य में स्पष्ट रूप से स्थानांतरित करने का विकल्प देता है, साथ ही यदि आप जानते हैं कि इसे कभी भी कॉलिंग संदर्भ में उपयोग नहीं किया जाएगा।
  2. क्या कार्यक्षमता केवल स्ट्रिंग को पढ़ती है? यदि ऐसा है तो उपयोग std::string_view(स्थिरांक, गैर रेफरी) इस वजह से string_viewसंभाल कर सकते हैं std::stringऔर char*बिना किसी समस्या के और एक प्रतिलिपि बनाने के बिना आसानी से। यह सभी const std::string&मापदंडों को प्रतिस्थापित करना चाहिए ।

अंततः आपको कंस्ट्रक्टर को कभी भी कॉल करने की आवश्यकता नहीं है std::string_viewजैसे आप हैं। std::stringएक रूपांतरण ऑपरेटर है जो रूपांतरण को स्वचालित रूप से संभालता है।


बस एक बिंदु को स्पष्ट करने के लिए, मैं सोच रहा हूं कि ऐसा रूपांतरण ऑपरेटर जीवनकाल के सबसे खराब मुद्दों का भी ध्यान रखेगा, यह सुनिश्चित करने से कि आपका आरएचएस स्ट्रिंग मूल्य कॉल की पूरी लंबाई के आसपास रहता है?
TED

3
@ यदि आप केवल मूल्य पढ़ रहे हैं तो मूल्य कॉल को नष्ट कर देगा। यदि आप स्वामित्व ले रहे हैं, तो उसे कॉल को अलग करना होगा। इसलिए मैंने दोनों मामलों को संबोधित किया। रूपांतरण ऑपरेटर केवल std::string_viewउपयोग करने में आसान बनाने से संबंधित है । यदि कोई डेवलपर किसी ऐसी स्थिति में इसका गलत उपयोग करता है जो प्रोग्रामिंग त्रुटि है। std::string_viewसख्ती से गैर-मालिक है।
मेट्ज

क्यों const, non-ref? कांस्टेबल होने का पैरामीटर विशिष्ट उपयोग तक है, लेकिन सामान्य रूप से गैर-कास्ट के रूप में उचित है। और आप चूक गए । स्लाइस स्वीकार कर सकते हैं
v.oddou

के const std::string_view &स्थान पर गुजरने में क्या समस्या है const std::string &?
ceztko

@ceztko यह पूरी तरह से अनावश्यक है और डेटा तक पहुँचने पर एक अतिरिक्त अप्रत्यक्ष जोड़ता है।
मगताज

15

std::string_view , const char*C ++ के कुछ लाभों को लाता है : इसके विपरीत std::string, एक string_view

  • स्मृति नहीं है,
  • स्मृति आवंटित नहीं करता है,
  • कुछ ऑफसेट पर एक मौजूदा स्ट्रिंग में इंगित कर सकते हैं, और
  • सूचक के अप्रत्यक्ष स्तर में एक से कम स्तर है std::string&

इसका मतलब यह है कि एक स्ट्रिंग_व्यू अक्सर कॉपियों से बच सकता है, बिना कच्चे पॉइंटर्स से निपटने के।

आधुनिक कोड में, फ़ंक्शन मापदंडों के std::string_viewलगभग सभी उपयोगों को बदलना चाहिए const std::string&std::stringरूपांतरण ऑपरेटर घोषित करने के बाद से यह एक स्रोत-संगत परिवर्तन होना चाहिएstd::string_view

सिर्फ इसलिए कि एक स्ट्रिंग दृश्य आपके विशिष्ट उपयोग के मामले में मदद नहीं करता है जहां आपको एक स्ट्रिंग बनाने की आवश्यकता होती है, इसका मतलब यह नहीं है कि यह सामान्य रूप से एक बुरा विचार है। C ++ मानक पुस्तकालय सुविधा के बजाय सामान्यता के लिए अनुकूलित किया जा सकता है। "कम सुरक्षित" तर्क धारण नहीं करता है, क्योंकि यह स्ट्रिंग व्यू को स्वयं बनाने के लिए आवश्यक नहीं होना चाहिए।


2
का बड़ा दोष std::string_viewएक c_str()विधि की अनुपस्थिति है , जिसके परिणामस्वरूप अनावश्यक, मध्यवर्ती std::stringवस्तुओं का निर्माण और आवंटन की आवश्यकता होती है। यह विशेष रूप से निम्न-स्तरीय एपीआई में एक समस्या है।
मथियास

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

@ माथियास, string_view :: data () मैच c_str () नहीं करता है?
एलेनियन

3
@ जीववाका सी स्ट्रिंग को शून्य-टर्मिनेट किया जाना है, लेकिन एक स्ट्रिंग व्यू का डेटा आमतौर पर शून्य-टर्मिनेटेड नहीं है क्योंकि यह एक मौजूदा स्ट्रिंग में इंगित करता है। उदाहरण के लिए, यदि हमारे पास एक स्ट्रिंग abcdef\0और एक स्ट्रिंग दृश्य है जो cdeप्रतिस्थापन पर इंगित करता है , eतो मूल स्ट्रिंग के पास होने के बाद कोई शून्य वर्ण नहीं है fमानक भी नोट: "डेटा () एक बफर कि अशक्त-समाप्त नहीं है करने के लिए एक सूचक वापस आ सकते हैं। इसलिए यह आम तौर पर एक फ़ंक्शन के लिए डेटा () पास करने के लिए एक गलती है जो सिर्फ एक कास्ट charT * लेता है और एक शून्य-समाप्त स्ट्रिंग की उम्मीद करता है। "
amon

1
@kayleeFrye_onDeck डेटा पहले से ही एक चार सूचक है। C स्ट्रिंग्स के साथ समस्या एक चार सूचक नहीं हो रही है, लेकिन यह कि C स्ट्रिंग को शून्य-समाप्त किया जाना चाहिए। एक उदाहरण के लिए मेरी पिछली टिप्पणी देखें।
आमोद

8

मुझे वह सलाह आश्चर्यजनक लगी, क्योंकि यह मुख्य रूप से अनुकूलन के प्रयोजनों के लिए कम सुरक्षित एक (मूल रूप से महिमा सूचक और लंबाई) के साथ एक अपेक्षाकृत सुरक्षित वस्तु की जगह सार्वभौमिक रूप से प्रतिस्थापित करने की वकालत करता प्रतीत होता है।

मुझे लगता है कि यह इस के उद्देश्य को थोड़ा गलत समझ रहा है। हालांकि यह एक "अनुकूलन" है, आपको वास्तव में इसके बारे में सोचना चाहिए कि अपने आप को एक का उपयोग करने से रोकना std::string

C ++ के उपयोगकर्ताओं ने दर्जनों बनाए हैं विभिन्न स्ट्रिंग कक्षाएं हैं। फिक्स्ड-लेंथ स्ट्रिंग क्लासेस, SSO- ऑप्टिमाइज्ड क्लासेस विथ बफर साइज दॅ टेम्पलेट टेम्पलेट, स्ट्रिंग क्लासेस जो हैश वैल्यू स्टोर करते हैं उनकी तुलना करने के लिए, आदि। कुछ लोग यहां तक ​​कि गाय-आधारित स्ट्रिंग्स का भी उपयोग करते हैं। यदि C ++ प्रोग्रामर को एक चीज पसंद है, तो वह स्ट्रिंग क्लासेस लिखना है।

और यह स्ट्रिंग की उपेक्षा करता है जो सी पुस्तकालयों द्वारा बनाई और स्वामित्व में हैं। नग्न char*एस, शायद किसी प्रकार के आकार के साथ।

इसलिए यदि आप कुछ पुस्तकालय लिख रहे हैं, और आप एक लेते हैं const std::string&, तो उपयोगकर्ता को अब जो भी स्ट्रिंग वे उपयोग कर रहे थे उसे लेना होगा और इसे कॉपी करना होगा std::string। शायद दर्जनों बार।

यदि आप std::stringस्ट्रिंग-विशिष्ट इंटरफ़ेस तक पहुँच चाहते हैं , तो आपको स्ट्रिंग की प्रतिलिपि क्यों बनानी चाहिए ? ऐसी बर्बादी है।

string_viewएक पैरामीटर के रूप में नहीं लेने के सिद्धांत कारण हैं:

  1. यदि आपका अंतिम लक्ष्य स्ट्रिंग को एक इंटरफ़ेस में पास करना है जो एनयूएल-टर्मिनेटेड स्ट्रिंग ( fopen, आदि) लेता है । std::stringएनयूएल समाप्त होने की गारंटी है; string_viewनहीं है। और इसे गैर-एनयूएल-समाप्त करने के लिए एक दृश्य को प्रतिस्थापित करना बहुत आसान है; सब-स्ट्रिंग एक std::stringप्रतिस्थापन को NUL-समाप्त सीमा में कॉपी करेगा।

    मैंने वास्तव में इस परिदृश्य के लिए एक विशेष NUL- समाप्त string_view शैली प्रकार लिखा था। आप अधिकांश ऑपरेशन कर सकते हैं, लेकिन वे नहीं जो इसकी एनयूएल-टर्मिनेटेड स्थिति (अंत से ट्रिमिंग, उदाहरण के लिए) को तोड़ते हैं।

  2. आजीवन मुद्दे। यदि आपको वास्तव में कॉपी करने की आवश्यकता है std::stringया अन्यथा फ़ंक्शन कॉल को वर्णों के सरणी से बाहर किया गया है, तो इसे लेने के लिए इस अप-फ्रंट को बताना सबसे अच्छा है const std::string &। या सिर्फ एक std::stringमान पैरामीटर के रूप में। इस तरह, अगर उनके पास पहले से ही इस तरह की स्ट्रिंग है, तो आप तुरंत इसके स्वामित्व का दावा कर सकते हैं, और कॉलर को स्ट्रिंग में स्थानांतरित कर सकते हैं यदि उन्हें इसके बारे में प्रतिलिपि रखने की आवश्यकता नहीं है।


क्या ये सच है? केवल मानक स्ट्रिंग वर्ग I के बारे में पता था C ++ से पहले यह std :: string था। सी के साथ पिछड़े संगतता के लिए "स्ट्रिंग्स" के रूप में चार * के उपयोग के लिए कुछ समर्थन है, लेकिन मुझे लगभग कभी भी इसका उपयोग करने की आवश्यकता नहीं है। निश्चित रूप से, लगभग किसी भी चीज़ की आप कल्पना कर सकते हैं, जिसके लिए बहुत सारे उपयोगकर्ता-परिभाषित थर्ड पार्टी क्लासेस हैं, और स्ट्रिंग्स शायद उसी में शामिल हैं, लेकिन मुझे लगभग कभी भी उन का उपयोग नहीं करना पड़ता है।
TED

@ टेड: सिर्फ इसलिए कि आप "लगभग कभी भी उन का उपयोग नहीं करते हैं" इसका मतलब यह नहीं है कि अन्य लोग नियमित रूप से उनका उपयोग नहीं करते हैं। string_viewएक लिंगुआ फ्रैंका प्रकार है जो किसी भी चीज़ के साथ काम कर सकता है।
निकोल बोलस

3
@ टेड: यही कारण है कि मैंने "C ++ को एक प्रोग्रामिंग वातावरण के रूप में" कहा, "C ++ को भाषा / लाइब्रेरी के रूप में विरोध किया।"
निकोल बोलस

2
@TED: " तो मैं समान रूप से कह सकता हूं" C ++ एक प्रोग्रामिंग वातावरण के रूप में हजारों कंटेनर कक्षाएं हैं? "और यह करता है। लेकिन मैं एल्गोरिदम लिख सकता हूं जो पुनरावृत्तियों के साथ काम करता है, और किसी भी कंटेनर वर्ग जो उस प्रतिमान का पालन करते हैं, उनके साथ काम करेंगे। इसके विपरीत, "एल्गोरिदम" जो किसी भी वर्ण की सरणी ले सकता है लिखने के लिए बहुत कठिन थे। के साथ string_view, यह आसान है।
निकोल बोलस

1
@TED: कैरेक्टर एरे बहुत खास मामला है। वे अत्यधिक सामान्य हैं, और सन्निहित पात्रों के विभिन्न कंटेनर केवल इस बात में भिन्न होते हैं कि वे अपनी स्मृति को कैसे प्रबंधित करते हैं, न कि कैसे आप डेटा में पुनरावृति करते हैं। तो एक एकल लिंगुआ फ्रेंका श्रेणी प्रकार होने से ऐसे सभी मामलों को कवर किया जा सकता है बिना किसी टेम्पलेट को नियोजित करने के लिए समझ में आता है। इससे परे सामान्यीकरण रेंज टीएस और टेम्पलेट्स का प्रांत है।
निकोल बोलस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.