कास्ट स्टैड :: स्ट्रिंग और पैरामीटर के रूप में गुजरने के दिन हैं?


604

मैं हर्ब Sutter द्वारा हाल ही में एक बात जो सुझाव दिया है कि कारणों पारित करने के लिए सुना std::vectorऔर std::stringसे const &काफी हद तक चले गए हैं। उन्होंने सुझाव दिया कि निम्नलिखित के रूप में एक समारोह लिखना अब बेहतर है:

std::string do_something ( std::string inval )
{
   std::string return_val;
   // ... do stuff ...
   return return_val;
}

मैं समझता हूं कि इस return_valसमारोह में प्रतिफल की वापसी होगी और इसलिए कदम शब्दार्थ का उपयोग करके लौटाया जा सकता है, जो बहुत सस्ते हैं। हालांकि, invalअभी भी एक संदर्भ के आकार की तुलना में बहुत बड़ा है (जो आमतौर पर एक संकेतक के रूप में लागू किया जाता है)। ऐसा इसलिए है क्योंकि std::stringढेर में पॉइंटर सहित विभिन्न घटक हैं और char[]शॉर्ट स्ट्रिंग ऑप्टिमाइज़ेशन के लिए सदस्य हैं । इसलिए मुझे लगता है कि संदर्भ से गुजरना अभी भी एक अच्छा विचार है।

क्या कोई समझा सकता है कि हर्ब ने ऐसा क्यों कहा होगा?


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

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

3
@Sz। मैं नकली और बंद के रूप में गलत तरीके से वर्गीकृत किए जा रहे सवालों के प्रति संवेदनशील हूं। मुझे इस मामले का विवरण याद नहीं है और मैंने उनकी पुन: समीक्षा नहीं की है। इसके बजाय मैं बस इस धारणा पर अपनी टिप्पणी को हटाने जा रहा हूं कि मैंने गलती की। इसे मेरे ध्यान में लाने के लिए धन्यवाद।
हावर्ड हिनान्ट

2
@HowardHinnant, आपका बहुत-बहुत धन्यवाद, यह हमेशा एक अनमोल क्षण होता है, जब कोई इस स्तर पर ध्यान और संवेदनशीलता के साथ आता है, यह बहुत ताज़ा होता है! (मैं फिर से, मुझे हटा दूँगा।)
एसजेड।

जवाबों:


393

हर्ब ने जो कहा, वह इस तरह के मामलों के कारण है।

मान लीजिए कि मेरे पास फ़ंक्शन है Aजो फ़ंक्शन को कॉल करता है B, जो फ़ंक्शन को कॉल करता है C। और Aके माध्यम से एक स्ट्रिंग से गुजरता है Bऔर में CAपता नहीं है या परवाह नहीं है C; सभी के Aबारे में जानता है B। यह Cएक कार्यान्वयन विवरण हैB

मान लीजिए कि A को इस प्रकार परिभाषित किया गया है:

void A()
{
  B("value");
}

यदि B और C स्ट्रिंग को लेते हैं const&, तो यह कुछ इस तरह दिखता है:

void B(const std::string &str)
{
  C(str);
}

void C(const std::string &str)
{
  //Do something with `str`. Does not store it.
}

सब अच्छा और अच्छा। आप बस चारों ओर से गुजर रहे हैं, कोई नकल नहीं कर रहा है, कोई हिल नहीं रहा है, हर कोई खुश है। Cलिया जाता है एकconst& , क्योंकि यह स्ट्रिंग की दुकान नहीं है। यह बस इसका उपयोग करता है।

अब, मैं एक सरल परिवर्तन करना चाहता हूं: Cस्ट्रिंग को कहीं स्टोर करने की आवश्यकता है।

void C(const std::string &str)
{
  //Do something with `str`.
  m_str = str;
}

हैलो, कॉपी कंस्ट्रक्टर और संभावित मेमोरी एलोकेशन ( शॉर्ट स्ट्रिंग ऑप्टिमाइज़ेशन (SSO) को अनदेखा करें )। C ++ 11 के चाल शब्दार्थों को अनावश्यक कॉपी-कंस्ट्रक्शन को हटाने के लिए संभव माना जाता है? और Aएक अस्थायी गुजरता है; डेटा Cको कॉपी करने के लिए कोई कारण नहीं होना चाहिए । उसे बस उसी के साथ फरार होना चाहिए जो उसे दिया गया था।

सिवाय यह नहीं कर सकते। क्योंकि यह एक लेता है const&

यदि मैं Cइसके पैरामीटर को मान से बदलता हूं , तो बस Bउस पैरामीटर में कॉपी करने का कारण बनता है; मुझे कुछ नहीं मिला।

तो अगर मैं अभी strतक सभी कार्यों के माध्यम से मूल्य से गुजरता था , तो भरोसा करनाstd::move तो डेटा के चारों ओर फेरबदल करने के लिए करना, हमें यह समस्या नहीं होगी। अगर कोई इसे पकड़ना चाहता है, तो वे कर सकते हैं। यदि वे नहीं करते हैं, तो ठीक है।

क्या यह अधिक महंगा है? हाँ; एक मूल्य में जाना संदर्भों का उपयोग करने की तुलना में अधिक महंगा है। क्या यह कॉपी से कम महंगा है? एसएसओ के साथ छोटे तार के लिए नहीं। क्या यह करने योग्य है?

यह आपके उपयोग के मामले पर निर्भर करता है। आप मेमोरी आवंटन से कितनी नफरत करते हैं?


2
जब आप कहते हैं कि मान का उपयोग करना संदर्भों की तुलना में अधिक महंगा है, तो यह स्थिर राशि (स्ट्रिंग की लंबाई से स्वतंत्र होने के कारण) अभी भी अधिक महंगा है?
नील जी

3
@ नील: क्या आप समझते हैं कि "कार्यान्वयन-निर्भर" का क्या अर्थ है? आप जो कह रहे हैं वह गलत है, क्योंकि यह इस बात पर निर्भर करता है कि क्या और कैसे एसएसओ लागू किया जाता है।
iljarn

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

8
@ नील: निश्चित रूप से, लेकिन आपका मूल प्रश्न था " यह अभी भी एक स्थिर राशि से अधिक महंगा है (स्ट्रिंग की लंबाई से स्वतंत्र स्थानांतरित किया जा रहा है) सही? " मैं जिस बिंदु को बनाने की कोशिश कर रहा हूं, वह अलग से अधिक महंगा हो सकता है? स्ट्रिंग की लंबाई के आधार पर निरंतर मात्रा, जो "नहीं" के रूप में अभिव्यक्त होती है।
iljarn

13
movedमान के मामले में स्ट्रिंग B से C तक क्यों होगी ? यदि B है B(std::string b)और C है C(std::string c)तो या तो हमें C(std::move(b))B में कॉल करना होगा या बाहर bरहना होगा (इस प्रकार 'unmoved से') बाहर निकलते समय B। (शायद एक अनुकूलन करने वाला कंपाइलर स्ट्रिंग के रूप में-अगर नियम के तहत bकॉल के बाद उपयोग नहीं किया जाता है, लेकिन मुझे नहीं लगता कि एक मजबूत गारंटी है।) की प्रतिलिपि के strलिए भी यही सच है m_str। भले ही एक फ़ंक्शन पैरामिटर को एक प्रतिद्वंद्विता के साथ आरंभ किया गया था, यह फ़ंक्शन के अंदर एक अंतराल है और std::moveउस अंतराल से स्थानांतरित करने के लिए आवश्यक है।
Pixelchemist

163

कास्ट स्टैड :: स्ट्रिंग और पैरामीटर के रूप में गुजरने के दिन हैं?

नहीं । कई लोग इस सलाह को (डेव अब्राहम सहित) उस डोमेन से परे लेते हैं, जिस पर यह लागू होता है, और इसे सभी std::string मापदंडों पर लागू करने के लिए सरल करता है - हमेशाstd::string मूल्य से गुजरना किसी भी और सभी मनमाने मापदंडों और अनुप्रयोगों के लिए "सर्वोत्तम अभ्यास" नहीं है क्योंकि ये अनुकूलन वार्ता / लेख केवल मामलों के प्रतिबंधित सेट पर लागू होते हैं

यदि आप कोई मान लौटा रहे हैं, तो पैरामीटर को म्यूट कर रहे हैं या मान ले रहे हैं, तो मूल्य से गुजरने से महंगी प्रतिलिपि को बचाया जा सकता है और वाक्यविन्यास सुविधा प्रदान की जा सकती है।

हमेशा की तरह, जब आपको कॉपी की आवश्यकता नहीं होती है तो कॉन्स्ट रेफरेंस से गुजरने से बहुत कॉपी बचती है

अब विशिष्ट उदाहरण के लिए:

हालाँकि, आक्रमण अभी भी एक संदर्भ के आकार की तुलना में काफी बड़ा है (जो आमतौर पर एक संकेतक के रूप में लागू किया जाता है)। ऐसा इसलिए है क्योंकि एक std :: string में पॉइंटर सहित विभिन्न घटक होते हैं और शॉर्ट स्ट्रिंग ऑप्टिमाइज़ेशन के लिए एक सदस्य char []। इसलिए मुझे लगता है कि संदर्भ से गुजरना अभी भी एक अच्छा विचार है। क्या कोई समझा सकता है कि हर्ब ने ऐसा क्यों कहा होगा?

यदि स्टैक का आकार एक चिंता है (और यह मानकर इनलेटेड / ऑप्टिमाइज़ नहीं किया गया है), return_val+ inval> return_val- IOW, पीक स्टैक का उपयोग यहां मूल्य से गुजरकर कम किया जा सकता है (ध्यान दें: ABI का निरीक्षण)। इस बीच, कॉन्स्टिट्यूशन पास करके ऑप्टिमाइजेशन को डिसेबल कर सकते हैं। यहां प्राथमिक कारण स्टैक वृद्धि से बचने के लिए नहीं है, लेकिन यह सुनिश्चित करने के लिए कि जहां यह लागू है, वहां अनुकूलन किया जा सकता है

कॉन्स्ट रेफरेंस से गुजरने के दिन खत्म नहीं हुए हैं - नियम सिर्फ एक बार से ज्यादा जटिल थे। यदि प्रदर्शन महत्वपूर्ण है, तो आप इस बात पर विचार करने के लिए बुद्धिमान होंगे कि आप इन प्रकारों को कैसे पास करते हैं, आपके कार्यान्वयन में उपयोग किए गए विवरण के आधार पर।


3
स्टैक के उपयोग पर, विशिष्ट ABI बिना किसी स्टैक उपयोग के एक रजिस्टर में एक ही संदर्भ पारित करेंगे।
23

63

यह बहुत संकलक के कार्यान्वयन पर निर्भर करता है।

हालाँकि, यह इस बात पर भी निर्भर करता है कि आप क्या उपयोग करते हैं।

अगले कार्यों पर विचार करें:

bool foo1( const std::string v )
{
  return v.empty();
}
bool foo2( const std::string & v )
{
  return v.empty();
}

इन कार्यों को एक अलग संकलन इकाई में लागू किया जाता है ताकि इनलाइनिंग से बचा जा सके। तब:
1. यदि आप इन दो कार्यों के लिए शाब्दिक पास करते हैं, तो आपको प्रदर्शनों में बहुत अंतर नहीं दिखेगा। दोनों स्थितियों में, एक स्ट्रिंग ऑब्जेक्ट बनाया जाना है
। 2. यदि आप एक और एसटी :: स्ट्रिंग ऑब्जेक्ट पास करते हैं, foo2तो बेहतर प्रदर्शन करेंगे foo1, क्योंकि foo1यह एक गहरी कॉपी करेगा।

मेरे पीसी पर, g ++ 4.6.1 का उपयोग करते हुए, मुझे ये परिणाम मिले:

  • चर संदर्भ: 1000000000 पुनरावृत्तियों -> समय बीतने के बाद: 2.25912 सेकंड
  • परिवर्तनशील मूल्य: 1000000000 पुनरावृत्तियों -> समय समाप्त: 27.2259 सेकंड
  • शाब्दिक संदर्भ: 100000000 पुनरावृत्तियों -> समय समाप्त: 9.10319 सेकंड
  • मूल्य द्वारा शाब्दिक: 100000000 पुनरावृत्तियों -> समय समाप्त: 8.62659 सेकंड

4
क्या अधिक प्रासंगिक है जो फ़ंक्शन के अंदर हो रहा है : क्या यह होगा, अगर एक संदर्भ के साथ कहा जाता है, तो आंतरिक रूप से एक प्रतिलिपि बनाने की आवश्यकता होती है जिसे मूल्य से गुजरने पर छोड़ा जा सकता है ?
लेफ्टरनैबाउट

1
@leftractionabout हां, ऑफ कोर्स। मेरी धारणा है कि दोनों कार्य बिल्कुल एक ही काम कर रहे हैं।
B:02овиЈ

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

3
मेरे लिए "यह इस बात पर निर्भर करता है कि आप फ़ंक्शन के अंदर क्या करते हैं" खराब डिज़ाइन है - चूंकि आप कार्यान्वयन के आंतरिक पर फ़ंक्शन के हस्ताक्षर को आधार बना रहे हैं।
हंस ओल्सन

1
एक टाइपो हो सकता है, लेकिन पिछले दो शाब्दिक समय में 10x कम छोर हैं।
टैंकरस्मैश

54

संक्षिप्त उत्तर: नहीं! लंबा जवाब:

  • यदि आप स्ट्रिंग को संशोधित नहीं करेंगे (व्यवहार केवल पढ़ने के लिए है), तो इसे पास करें const ref&
    ( const ref&जाहिर है कि इसे इस्तेमाल करने वाले कार्यक्षेत्र के दायरे में रहना होगा)
  • यदि आप इसे संशोधित करने की योजना बनाते हैं या आप जानते हैं कि यह कार्यक्षेत्र (थ्रेड्स) से बाहर निकल जाएगा value, तो इसे पास करें , const ref&अपने फ़ंक्शन बॉडी के अंदर कॉपी न करें।

Cpp-next.com पर एक पोस्ट थी जिसे "गति चाहते हैं, मान से पास करें!" । टीएल; डीआर:

दिशानिर्देश : अपने कार्य तर्कों की नकल न करें। इसके बजाय, उन्हें मान से पास करें और कंपाइलर को कॉपी करने दें।

^ का स्थानांतरण

अपने फ़ंक्शन तर्क की प्रतिलिपि न करें --- का अर्थ है: यदि आप तर्क मान को आंतरिक चर में कॉपी करके संशोधित करने की योजना बनाते हैं, तो इसके बजाय केवल मान तर्क का उपयोग करें

तो, यह मत करो :

std::string function(const std::string& aString){
    auto vString(aString);
    vString.clear();
    return vString;
}

यह करो :

std::string function(std::string aString){
    aString.clear();
    return aString;
}

जब आपको अपने फ़ंक्शन बॉडी में तर्क मान को संशोधित करने की आवश्यकता होती है।

आपको बस यह जानना होगा कि आप फ़ंक्शन बॉडी में तर्क का उपयोग करने की योजना कैसे बनाते हैं। पढ़ें-केवल या नहीं ... और अगर यह दायरे में रहता है।


2
आप कुछ मामलों में संदर्भ से गुजरने की सलाह देते हैं, लेकिन आप एक दिशानिर्देश की ओर इशारा करते हैं जो हमेशा मूल्य से गुजरने की सलाह देता है।
कीथ थॉम्पसन

3
@KeithThompson अपने फ़ंक्शन तर्क की प्रतिलिपि न करें। इसका मतलब const ref&यह संशोधित करने के लिए एक आंतरिक चर की नकल नहीं है। यदि आपको इसे संशोधित करने की आवश्यकता है ... पैरामीटर को एक मूल्य बनाएं। यह मेरे गैर-अंग्रेजी बोलने वाले स्व के लिए बल्कि स्पष्ट है।
कोडएग्री

5
@KeithThompson गाइडलाइन उद्धरण (अपने फ़ंक्शन तर्कों को कॉपी न करें। इसके बजाय, उन्हें मान से पास करें और कंपाइलर को कॉपी करने दें।) उस पेज से कॉपी किया गया है। यदि यह पर्याप्त स्पष्ट नहीं है, तो मैं मदद नहीं कर सकता। मैं पूरी तरह से सबसे अच्छा विकल्प बनाने के लिए संकलक पर भरोसा नहीं करता। मैं समारोह के तर्कों को परिभाषित करने के तरीके में अपने इरादों के बारे में बहुत स्पष्ट होना चाहूंगा। # 1 यदि यह केवल पढ़ने के लिए है, तो यह एक है const ref&। # 2 अगर मुझे इसे लिखने की आवश्यकता है या मुझे पता है कि यह दायरे से बाहर हो जाता है ... मैं एक मूल्य का उपयोग करता हूं। # 3 अगर मुझे मूल मूल्य को संशोधित करने की आवश्यकता है, तो मैं इसके माध्यम से गुजरता हूं ref&। # 4 pointers *यदि कोई तर्क वैकल्पिक है तो मैं nullptrइसका उपयोग कर सकता हूं ।
कोडएग्री

11
मैं मूल्य या संदर्भ द्वारा पारित करने के सवाल पर पक्ष नहीं ले रहा हूं। मेरा कहना है कि आप कुछ मामलों में संदर्भ से गुजरने की वकालत करते हैं, लेकिन फिर एक दिशानिर्देश का हवाला देते हुए (हमेशा अपनी स्थिति का समर्थन करने के लिए) हवाला देते हैं जो हमेशा मूल्य से गुजरने की सलाह देता है। यदि आप दिशानिर्देश से असहमत हैं, तो आप ऐसा कहना चाहते हैं और क्यों समझा सकते हैं। (Cpp-next.com के लिंक मेरे लिए काम नहीं कर रहे हैं।)
कीथ थॉम्पसन

4
@KeithThompson: आप दिशानिर्देश को गलत बता रहे हैं। यह मूल्य से "हमेशा" गुजरना नहीं है। संक्षेप में, यह था कि "यदि आपने एक स्थानीय प्रति बनायी होती, तो संकलक आपके पास उस प्रति का प्रदर्शन करने के लिए मान द्वारा पास का उपयोग करता।" जब आप प्रतिलिपि बनाने के लिए नहीं जा रहे थे तो यह पास-दर-मूल्य का उपयोग करने के लिए नहीं कह रहा है।
बेन वोइग्ट

43

जब तक आपको वास्तव में एक प्रतिलिपि की आवश्यकता नहीं होती है तब भी इसे लेना उचित है const &। उदाहरण के लिए:

bool isprint(std::string const &s) {
    return all_of(begin(s),end(s),(bool(*)(char))isprint);
}

यदि आप इसे स्ट्रिंग द्वारा मान लेने के लिए बदलते हैं तो आप पैरामीटर को स्थानांतरित करना या कॉपी करना समाप्त कर देंगे, और इसके लिए कोई आवश्यकता नहीं है। न केवल प्रतिलिपि / चाल की संभावना अधिक महंगी है, बल्कि यह एक नई संभावित विफलता का भी परिचय देती है; प्रतिलिपि / चाल एक अपवाद फेंक सकती है (उदाहरण के लिए, प्रतिलिपि के दौरान आवंटन विफल हो सकता है) जबकि मौजूदा मान का संदर्भ नहीं ले सकता।

यदि आप करते हैं एक प्रति की जरूरत तो गुजर और मूल्य से लौटने आमतौर पर है (हमेशा?) सबसे अच्छा विकल्प। वास्तव में मैं आमतौर पर C ++ 03 में इसके बारे में चिंता नहीं करता, जब तक कि आप नहीं पाते कि अतिरिक्त प्रतियां वास्तव में एक प्रदर्शन समस्या का कारण बनती हैं। प्रतिलिपि संकलक आधुनिक संकलक पर बहुत विश्वसनीय लगता है। मुझे लगता है कि लोगों की शंका और जिद कि आपको आरवीओ के लिए कंपाइलर सपोर्ट के अपने टेबल को जांचना होगा, आजकल ज्यादातर अप्रचलित है।


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


2
मूव कंस्ट्रक्टर आमतौर पर के साथ लागू किए जाते हैं noexcept, लेकिन स्पष्ट रूप से कॉपी कंस्ट्रक्टर नहीं होते हैं।
लेफ्टरेंबाउट

25

लगभग।

सी ++ 17 में, हमारे पास है basic_string_view<?>, जो हमें मूल रूप से एक संकीर्ण उपयोग के मामले में नीचे लाता हैstd::string const& मापदंडों के ।

चाल शब्दार्थों के अस्तित्व ने इसके लिए एक उपयोग के मामले को समाप्त कर दिया है std::string const&- यदि आप पैरामीटर को संचय करने की योजना बना रहे हैं, तो एक std::stringबाय वैल्यू लेना अधिक इष्टतम है, जैसा कि आप कर सकते हैंmove पैरामीटर से बाहर हैं।

यदि किसी ने आपके फ़ंक्शन को कच्चे C के साथ बुलाया है "string"तो इसका मतलब है कि केवल एक std::stringबफर को कभी भी आवंटित किया जाता है, जैसा कि std::string const&मामले में दो के विपरीत है ।

हालाँकि, यदि आप एक प्रतिलिपि बनाने का इरादा नहीं रखते हैं, तब तक लेना std::string const&C ++ 14 में अभी भी उपयोगी है।

जब std::string_viewतक आप एक स्ट्रिंग को एपीआई से नहीं '\0'जोड़ रहे हैं, जो सी-स्टाइल-से- कैरेक्टर बफ़र्स की अपेक्षा करता है , तब तक आप std::stringकिसी भी आवंटन को जोखिम में डाले बिना कार्यक्षमता की तरह अधिक कुशलता से प्राप्त कर सकते हैं । एक कच्चे सी स्ट्रिंग को std::string_viewबिना किसी आवंटन या चरित्र की नकल के भी चालू किया जा सकता है ।

उस बिंदु पर, उपयोग std::string const&तब होता है जब आप डेटा थोक की प्रतिलिपि नहीं बना रहे हैं, और इसे C- शैली API पर पास करने जा रहे हैं जो एक शून्य समाप्त बफर की उम्मीद करता है, और आपको उच्च स्तरीय स्ट्रिंग फ़ंक्शन std::stringप्रदान करने की आवश्यकता है। व्यवहार में, यह आवश्यकताओं का एक दुर्लभ समूह है।


2
मैं इस उत्तर की सराहना करता हूं - लेकिन मैं इसे इंगित करना चाहता हूं कि यह थोड़े से डोमेन-विशिष्ट मान से पीड़ित है (जैसा कि कई गुणवत्ता उत्तर करते हैं)। बुद्धि के लिए: "व्यवहार में, यह आवश्यकताओं का एक दुर्लभ सेट है" ... मेरे स्वयं के विकास के अनुभव में, इन बाधाओं - जो लेखक को असामान्य रूप से संकीर्ण लगते हैं - जैसे, शाब्दिक रूप से हर समय मिलते हैं। यह इस ओर इशारा करने लायक है।
फिशवॉच

1
@ fish2000 स्पष्ट होने के लिए, std::stringआप पर हावी होने के लिए उन आवश्यकताओं में से कुछ की आवश्यकता नहीं है, लेकिन उनमें से सभी । उनमें से कोई एक या दो भी है, मैं मानता हूँ, आम। हो सकता है कि आपको आमतौर पर सभी 3 की आवश्यकता होती है (जैसे, आप एक स्ट्रिंग तर्क के कुछ पार्सिंग कर रहे हैं जिसे चुनने के लिए आप जिस सी एपीआई को थोक में पास करने जा रहे हैं?)
यक - एडम नेवरामॉन्ट

@ यक-आदमनेवरुमोंट यह एक वाईएमवीवी चीज है - लेकिन यह एक लगातार उपयोग का मामला है अगर (कहें) आप पोसिक्स के खिलाफ प्रोग्रामिंग कर रहे हैं, या अन्य एपीआई जहां सी-स्ट्रिंग शब्दार्थ हैं, जैसे, सबसे कम सामान्य द्विघात। मुझे वास्तव में कहना चाहिए कि मैं प्यार करता हूं std::string_view- जैसा कि आप बताते हैं, "एक कच्ची सी स्ट्रिंग को भी एक std में बदल दिया जा सकता है :: string_view बिना किसी आवंटन या चरित्र की नकल के" जो कि उन लोगों को याद रखने के लायक है जो C ++ के संदर्भ में उपयोग कर रहे हैं इस तरह के एपीआई का उपयोग, वास्तव में।
मछली का बच्चा सेप

1
@ fish2000 "'एक कच्चा सी स्ट्रिंग भी एक std में बदल सकता है :: string_view बिना किसी आवंटन या चरित्र की नकल के' जो कुछ याद रखने लायक है"। वास्तव में, लेकिन यह सबसे अच्छा हिस्सा छोड़ देता है - इस मामले में कि कच्ची स्ट्रिंग एक स्ट्रिंग शाब्दिक है, इसके लिए रनटाइम स्ट्रलेन () की भी आवश्यकता नहीं होती है !
डॉन हैच

17

std::stringनहीं है सादा पुराना डाटा (पॉड) , और इसके कच्चे आकार सबसे अधिक प्रासंगिक बात कभी नहीं है। उदाहरण के लिए, यदि आप एक स्ट्रिंग में गुजरते हैं जो एसएसओ की लंबाई से ऊपर है और ढेर पर आवंटित की जाती है, तो मैं उम्मीद करता हूं कि कॉपी निर्माता एसएसओ स्टोरेज की नकल नहीं करेगा।

इसका कारण यह अनुशंसा की जाती है क्योंकि invalतर्क अभिव्यक्ति से निर्मित है, और इस प्रकार हमेशा ले जाया जाता है या उपयुक्त के रूप में कॉपी किया जाता है- कोई भी प्रदर्शन हानि नहीं है, यह मानते हुए कि आपको तर्क के स्वामित्व की आवश्यकता है। यदि आप नहीं करते हैं, तो एक constसंदर्भ अभी भी बेहतर तरीका हो सकता है।


2
कॉपी कंस्ट्रक्टर के बारे में दिलचस्प बात यह है कि अगर वह इसका उपयोग नहीं कर रहा है तो एसएसओ के बारे में चिंता न करें। शायद सही है, मैं जाँचने जा रहा हूँ कि क्या यह सच है ;-)
बेंज

3
@Benj: पुरानी टिप्पणी जो मुझे पता है, लेकिन अगर SSO छोटा है तो बिना शर्त इसे कॉपी करना सशर्त शाखा करने की तुलना में तेज़ है। उदाहरण के लिए, 64 बाइट्स एक कैशे लाइन है और इसे वास्तव में तुच्छ राशि में कॉपी किया जा सकता है। शायद x86_64 पर 8 चक्र या उससे कम।
ज़ैन लिंक्स

यहां तक ​​कि अगर एसएसओ को कॉपी कंस्ट्रक्टर द्वारा कॉपी नहीं किया जाता है, तो एक std::string<>32 बाइट्स है जो स्टैक से आवंटित किया जाता है, जिनमें से 16 को इनिशियलाइज़ करने की आवश्यकता होती है। इसकी तुलना केवल 8 बाइट्स के लिए करें और एक संदर्भ के लिए इसे आरंभीकृत करें: यह सीपीयू के काम से दोगुना है, और यह चार गुना अधिक कैशे स्पेस लेता है जो अन्य डेटा के लिए उपलब्ध नहीं होगा।
cmaster - मोनिका

ओह, और मैं रजिस्टरों में फ़ंक्शन तर्कों को पारित करने के बारे में बात करना भूल गया; यह पिछले कैली के लिए संदर्भ के स्टैक उपयोग को शून्य तक ले
आएगा

16

मैंने इस प्रश्न का उत्तर यहां कॉपी / पेस्ट किया है, और इस प्रश्न को फिट करने के लिए नामों और वर्तनी को बदल दिया है।

यहाँ कोड को मापने के लिए कहा जा रहा है:

#include <iostream>

struct string
{
    string() {}
    string(const string&) {std::cout << "string(const string&)\n";}
    string& operator=(const string&) {std::cout << "string& operator=(const string&)\n";return *this;}
#if (__has_feature(cxx_rvalue_references))
    string(string&&) {std::cout << "string(string&&)\n";}
    string& operator=(string&&) {std::cout << "string& operator=(string&&)\n";return *this;}
#endif

};

#if PROCESS == 1

string
do_something(string inval)
{
    // do stuff
    return inval;
}

#elif PROCESS == 2

string
do_something(const string& inval)
{
    string return_val = inval;
    // do stuff
    return return_val; 
}

#if (__has_feature(cxx_rvalue_references))

string
do_something(string&& inval)
{
    // do stuff
    return std::move(inval);
}

#endif

#endif

string source() {return string();}

int main()
{
    std::cout << "do_something with lvalue:\n\n";
    string x;
    string t = do_something(x);
#if (__has_feature(cxx_rvalue_references))
    std::cout << "\ndo_something with xvalue:\n\n";
    string u = do_something(std::move(x));
#endif
    std::cout << "\ndo_something with prvalue:\n\n";
    string v = do_something(source());
}

मेरे लिए यह आउटपुट:

$ clang++ -std=c++11 -stdlib=libc++ -DPROCESS=1 test.cpp
$ a.out
do_something with lvalue:

string(const string&)
string(string&&)

do_something with xvalue:

string(string&&)
string(string&&)

do_something with prvalue:

string(string&&)
$ clang++ -std=c++11 -stdlib=libc++ -DPROCESS=2 test.cpp
$ a.out
do_something with lvalue:

string(const string&)

do_something with xvalue:

string(string&&)

do_something with prvalue:

string(string&&)

नीचे दी गई तालिका मेरे परिणामों को संक्षिप्त करती है (क्लैंग -स्टीडी = सी ++ 11 का उपयोग करके)। पहली संख्या प्रतिलिपि निर्माणों की संख्या है और दूसरी संख्या चाल निर्माणों की संख्या है:

+----+--------+--------+---------+
|    | lvalue | xvalue | prvalue |
+----+--------+--------+---------+
| p1 |  1/1   |  0/2   |   0/1   |
+----+--------+--------+---------+
| p2 |  1/0   |  0/1   |   0/1   |
+----+--------+--------+---------+

पास-बाय-वैल्यू सॉल्यूशन के लिए केवल एक अधिभार की आवश्यकता होती है, लेकिन लेवल और xvalues ​​पास करते समय एक अतिरिक्त चाल निर्माण की लागत होती है। यह किसी भी स्थिति के लिए स्वीकार्य हो सकता है या नहीं भी हो सकता है। दोनों समाधानों के फायदे और नुकसान हैं।


1
std :: string एक मानक लाइब्रेरी क्लास है। यह पहले से ही चल और प्रतिलिपि दोनों है। मैं यह नहीं देखता कि यह कैसे प्रासंगिक है। ओपी मूव बनाम रेफरेंस के प्रदर्शन के बारे में अधिक पूछ रहा है , न कि मूव बनाम कॉपी के प्रदर्शन के बारे में।
निकोल बोल्स

3
यह उत्तर चालों की संख्या को गिनता है और एक std को कॉपी करता है :: स्ट्रिंग हर्ब और डेव दोनों द्वारा वर्णित पास-बाय-वैल्यू डिज़ाइन के तहत गुजरेगी, बनाम ओवरलोड कार्यों की एक जोड़ी के साथ संदर्भ से गुजरती है। मैं डेमो में ओपी कोड का उपयोग करता हूं, डमी स्ट्रिंग में प्रतिस्थापित करने के अलावा चिल्लाने के लिए जब इसे कॉपी / स्थानांतरित किया जा रहा हो।
हावर्ड हिनान्ट

परीक्षण करने से पहले आपको शायद कोड का अनुकूलन करना चाहिए ...
पैरामैग्नेटिक क्रोइसैंट

3
@ TheParamagneticCroissant: क्या आपको अलग परिणाम मिले? यदि हां, तो क्या कमांड लाइन तर्क के साथ क्या संकलक का उपयोग कर?
How पर हावर्ड हिनान्ट '

14

const std::string&एक प्रकार का पैरामीटर के रूप में सिफारिश करने में, बार्ज़ेन स्ट्रॉस्ट्रुप के साथ हर्ब सटर अभी भी रिकॉर्ड पर है ; देख https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rf-in

यहाँ किसी भी अन्य उत्तर में उल्लेख नहीं किया गया है: यदि आप एक const std::string&पैरामीटर को स्ट्रिंग शाब्दिक पास करते हैं, तो यह एक अस्थायी स्ट्रिंग के संदर्भ में पारित होगा, जो शाब्दिक के पात्रों को रखने के लिए ऑन-द-फ्लाई बनाया जाएगा। यदि आप उस संदर्भ को सहेजते हैं, तो अस्थायी स्ट्रिंग को हटाए जाने के बाद यह अमान्य हो जाएगा। सुरक्षित होने के लिए, आपको एक प्रति सहेजनी होगी , संदर्भ नहीं। समस्या इस तथ्य से उपजी है कि स्ट्रिंग शाब्दिक const char[N]प्रकार हैं, को बढ़ावा देने की आवश्यकता होती हैstd::string

नीचे दिया गया कोड मामूली दक्षता विकल्प के साथ-साथ पिटफॉल और वर्कअराउंड को दिखाता है - एक const char*विधि के साथ ओवरलोडिंग , जैसा कि सी ++ में संदर्भ के रूप में एक स्ट्रिंग शाब्दिक पास करने का एक तरीका है

(नोट: सटर एंड स्ट्रॉस्टग्रुप सलाह देता है कि यदि आप स्ट्रिंग की एक प्रति रखते हैं, तो && पैरामीटर और std :: move () के साथ एक अतिभारित फ़ंक्शन भी प्रदान करें।)

#include <string>
#include <iostream>
class WidgetBadRef {
public:
    WidgetBadRef(const std::string& s) : myStrRef(s)  // copy the reference...
    {}

    const std::string& myStrRef;    // might be a reference to a temporary (oops!)
};

class WidgetSafeCopy {
public:
    WidgetSafeCopy(const std::string& s) : myStrCopy(s)
            // constructor for string references; copy the string
    {std::cout << "const std::string& constructor\n";}

    WidgetSafeCopy(const char* cs) : myStrCopy(cs)
            // constructor for string literals (and char arrays);
            // for minor efficiency only;
            // create the std::string directly from the chars
    {std::cout << "const char * constructor\n";}

    const std::string myStrCopy;    // save a copy, not a reference!
};

int main() {
    WidgetBadRef w1("First string");
    WidgetSafeCopy w2("Second string"); // uses the const char* constructor, no temp string
    WidgetSafeCopy w3(w2.myStrCopy);    // uses the String reference constructor
    std::cout << w1.myStrRef << "\n";   // garbage out
    std::cout << w2.myStrCopy << "\n";  // OK
    std::cout << w3.myStrCopy << "\n";  // OK
}

उत्पादन:

const char * constructor
const std::string& constructor

Second string
Second string

यह एक अलग मुद्दा है और WidgetBadRef को गलत होने के लिए एक const और पैरामीटर की आवश्यकता नहीं है। सवाल यह है कि अगर WidgetSafeCopy ने सिर्फ एक स्ट्रिंग पैरामीटर लिया तो क्या यह धीमा होगा? (मुझे लगता है कि सदस्य को अस्थाई रूप से कॉपी करना निश्चित रूप से आसान है)
सुपरफिक जॉन

ध्यान दें कि T&&हमेशा एक सार्वभौमिक संदर्भ नहीं होता है; वास्तव में, std::string&&हमेशा एक रैवेले संदर्भ होगा, और कभी भी एक सार्वभौमिक संदर्भ नहीं होगा, क्योंकि किसी भी प्रकार की कटौती नहीं की जाती है । इस प्रकार, स्ट्रॉस्टग्रुप और सटर की सलाह मेयर्स के साथ संघर्ष नहीं करती है।
जस्टिन टाइम -

@JustinTime: धन्यवाद; मैंने यह दावा करते हुए गलत अंतिम वाक्य को हटा दिया कि वास्तव में, यह std :: string && एक सार्वभौमिक संदर्भ होगा।
सर्कल

@ Circlepi314 आपका स्वागत है। यह बनाने के लिए एक आसान मिश्रण है, यह कभी-कभी भ्रमित हो सकता है कि क्या किसी भी दिए गए T&&एक सार्वभौमिक संदर्भ या गैर-कटौती किए गए प्रतिद्वंद्वियों का संदर्भ है; यह शायद स्पष्ट हो जाता अगर वे सार्वभौमिक संदर्भों (जैसे &&&, &और के संयोजन के रूप में &&) के लिए एक अलग प्रतीक पेश करते , लेकिन वह शायद मूर्खतापूर्ण लगता।
जस्टिन टाइम -

8

के लिए C ++ संदर्भ का उपयोग कर IMO std::string एक त्वरित और छोटा स्थानीय अनुकूलन है, जबकि मूल्य से गुजरना बेहतर वैश्विक अनुकूलन हो सकता है (या नहीं)।

तो इसका उत्तर है: यह परिस्थितियों पर निर्भर करता है:

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

6

देखें "हर्ब Sutter" आधुनिक सी ++ शैली की मूल बातें! अनिवार्य वापस " । अन्य विषयों के अलावा उन्होंने यह पैरामीटर गुजर सलाह है कि अतीत में दिया गया है, और नए विचारों कि सी ++ 11 के साथ में आते हैं और विशेष रूप से पर लग रहा है की समीक्षा मूल्य से तार गुजरने का विचार।

स्लाइड २४

मानदंड बताते हैं कि std::stringमूल्य के हिसाब से गुजरना , ऐसे मामलों में जहां फ़ंक्शन इसे वैसे भी कॉपी करेगा, काफी धीमा हो सकता है!

ऐसा इसलिए है क्योंकि आप इसे हमेशा एक पूर्ण प्रतिलिपि बनाने के लिए मजबूर कर रहे हैं (और फिर जगह में स्थानांतरित करें), जबकि const&संस्करण पुराने स्ट्रिंग को अपडेट करेगा जो पहले से आवंटित बफर का पुन: उपयोग कर सकता है।

उसकी स्लाइड 27 देखें: "सेट" कार्यों के लिए, विकल्प 1 वही है जो हमेशा से था। विकल्प 2, रैवेले संदर्भ के लिए एक अधिभार जोड़ता है, लेकिन यह एक दहनशील विस्फोट देता है यदि कई पैरामीटर हैं।

यह केवल "सिंक" मापदंडों के लिए है जहां एक स्ट्रिंग बनाई जानी चाहिए (इसका मौजूदा मूल्य नहीं बदला गया है) जो पास-दर-मूल्य चाल वैध है। यही है, कंस्ट्रक्टर जिसमें पैरामीटर सीधे मिलान प्रकार के सदस्य को शुरू करता है।

यदि आप यह देखना चाहते हैं कि आप इस बारे में चिंता करने में कितने गहरे जा सकते हैं, तो निकोलै जोसुटिस की प्रस्तुति देखें और उसके साथ सौभाग्य ( "परफेक्ट - डोन!") पिछले संस्करण के साथ गलती खोजने के बाद n कभी।


इसे मानक दिशानिर्देशों में .1F.15 के रूप में भी संक्षेपित किया गया है।


3

जैसा कि @ JDługosz टिप्पणियों में बताते हैं, हर्ब दूसरे में (बाद में?) बात करने की सलाह देता है, यहाँ से मोटे तौर पर देखें: https://youtu.be/xnqTKD8uD64?t=54m50s

उनकी सलाह केवल एक फ़ंक्शन के लिए मान मापदंडों का उपयोग करके उबलती है fजो तथाकथित सिंक तर्क लेती है, यह मानते हुए कि आप इन सिंक नियुक्तियों से निर्माण करेंगे।

यह सामान्य दृष्टिकोण fक्रमशः लैवल्यू और रिवेल्यू तर्कों के अनुरूप कार्यान्वयन की तुलना में केवल लेवल्यू और रिवेल्यू तर्क दोनों के लिए एक कदम निर्माणकर्ता के ओवरहेड को जोड़ता है। यह देखने के लिए कि ऐसा क्यों है, मान लीजिए कि fएक मान पैरामीटर है, जहां Tकुछ प्रतिलिपि और रचनात्मक प्रकार स्थानांतरित होते हैं:

void f(T x) {
  T y{std::move(x)};
}

fएक लैवल्यू तर्क के साथ कॉल करने के परिणामस्वरूप एक कॉपी कंस्ट्रक्टर को निर्माण के लिए बुलाया जाएगा x, और एक निर्माण कंस्ट्रक्टर को निर्माण के लिए बुलाया जाएगा y। दूसरी ओर, fएक प्रतिद्वंद्विता के तर्क के साथ कॉल करने से एक निर्माण करने वाले को निर्माण करने के लिए बुलाया जाएगा x, और एक अन्य चाल निर्माणकर्ता को निर्माण के लिए बुलाया जाएगा y

सामान्य तौर पर, flvalue तर्कों के लिए इष्टतम कार्यान्वयन निम्नानुसार है:

void f(const T& x) {
  T y{x};
}

इस मामले में, केवल एक प्रतिलिपि निर्माता को निर्माण करने के लिए कहा जाता है yfआम तौर पर फिर से, तर्क तर्कों के लिए इष्टतम कार्यान्वयन है:

void f(T&& x) {
  T y{std::move(x)};
}

इस मामले में, केवल एक चाल निर्माणकर्ता को निर्माण करने के लिए कहा जाता है y

इसलिए एक समझदार समझौता एक मूल्य पैरामीटर लेना है और इष्टतम कार्यान्वयन के संबंध में या तो अंतराल या तर्क तर्कों के लिए एक अतिरिक्त चाल निर्माता कॉल है, जो हर्ब की बात में दी गई सलाह भी है।

जैसा कि @ JDługosz ने टिप्पणियों में बताया है, मूल्य से गुजरना केवल उन कार्यों के लिए समझ में आता है जो सिंक तर्क से कुछ ऑब्जेक्ट का निर्माण करेंगे। जब आपके पास एक फ़ंक्शन होता है fजो इसके तर्क की प्रतिलिपि बनाता है, तो पास-दर-मूल्य दृष्टिकोण सामान्य पास-बाय-कॉन्स्ट-रेफ़रेंस दृष्टिकोण की तुलना में अधिक ओवरहेड होगा। किसी फ़ंक्शन के लिए पास-दर-मूल्य दृष्टिकोण fजो उसके पैरामीटर की एक प्रति को बरकरार रखता है, उसके पास फ़ॉर्म होगा:

void f(T x) {
  T y{...};
  ...
  y = std::move(x);
}

इस मामले में, एक प्रतिवाद तर्क के लिए एक प्रतिलिपि निर्माण और एक चाल असाइनमेंट है, और एक चाल निर्माण और एक तर्क तर्क के लिए चाल असाइनमेंट है। एक तर्क तर्क के लिए सबसे इष्टतम मामला है:

void f(const T& x) {
  T y{...};
  ...
  y = x;
}

यह केवल एक असाइनमेंट के लिए उबालता है, जो पास-पास-मूल्य दृष्टिकोण के लिए आवश्यक कॉपी कंस्ट्रक्टर प्लस मूव असाइनमेंट की तुलना में बहुत सस्ता है। इसका कारण यह है कि असाइनमेंट मौजूदा आवंटित मेमोरी का पुन: उपयोग कर सकता हैy , और इसलिए (डी) आवंटन को रोक सकता है, जबकि कॉपी कंस्ट्रक्टर आमतौर पर मेमोरी आवंटित करेगा।

एक तर्क तर्क के लिए fकि प्रतिलिपि बनाए रखने के लिए सबसे इष्टतम कार्यान्वयन का रूप है:

void f(T&& x) {
  T y{...};
  ...
  y = std::move(x);
}

तो, इस मामले में केवल एक चाल असाइनमेंट। उस संस्करण के लिए एक अंतराल पारित करना एक कॉन्स्टिट्यूशन fलेता है केवल एक चाल असाइनमेंट के बजाय एक असाइनमेंट खर्च होता है। इतना अपेक्षाकृत, का संस्करणf सामान्य बात है कि सामान्य कार्यान्वयन के रूप में इस मामले में एक कास्ट संदर्भ लेने बेहतर है।

तो सामान्य तौर पर, सबसे इष्टतम कार्यान्वयन के लिए, आपको ओवरलोड करने या किसी प्रकार की सही अग्रेषण करने की आवश्यकता होगी जैसा कि बात में दिखाया गया है। दोष आपके लिए आवश्यक अधिभार की संख्या में एक दहनशील विस्फोट है, इस बात के लिए मापदंडों की संख्या के आधार पर कि fआप तर्क के मूल्य वर्ग पर अधिभार का विकल्प चुनते हैं। परफेक्ट फ़ॉरवर्डिंग में एक खामी है जो fएक टेम्प्लेट फ़ंक्शन बन जाता है, जो इसे आभासी बनाने से रोकता है, और यदि आप इसे 100% सही प्राप्त करना चाहते हैं, तो (अधिक विवरण कोड देखें)


मेरे नए उत्तर में हर्ब सटर के निष्कर्ष देखें: केवल तभी करें जब आप निर्माण को स्थानांतरित करते हैं, न कि असाइनमेंट को स्थानांतरित करें।
JDługosz

1
@ JDługosz, हर्ब की बात के लिए पॉइंटर के लिए धन्यवाद, मैंने इसे देखा और अपने जवाब को पूरी तरह से संशोधित किया। मुझे सलाह नहीं थी कि वह (चाल) सलाह दें।
टन वैन डेन हेउवेल

यह आंकड़ा और सलाह अब मानक दिशानिर्देश दस्तावेज़ में है।
JDługosz

1

समस्या यह है कि "कॉन्स्ट" एक गैर-ग्रैन्युलर क्वालीफ़ायर है। आमतौर पर "कास्ट स्ट्रिंग रेफरी" का अर्थ "इस स्ट्रिंग को संशोधित न करना" है, न कि "संदर्भ संख्या को संशोधित न करना"। सी ++ में बस यह कहने का कोई तरीका नहीं है कि कौन से सदस्य "कॉन्स्टेबल" हैं। वे या तो सभी हैं, या उनमें से कोई भी नहीं है।

आदेश में इस भाषा समस्या के समाधान को हैक करने में, एसटीएल सकता है "सी ()" अपने उदाहरण में एक कदम-अर्थ प्रतिलिपि बनाने के लिए अनुमति देते हैं वैसे भी संदर्भ गणना (परिवर्तनशील) के संबंध में "स्थिरांक" उपेक्षा, और कर्तव्यनिष्ठा। जब तक यह अच्छी तरह से निर्दिष्ट किया गया था, तब तक यह ठीक रहेगा।

चूंकि एसटीएल नहीं करता है, मेरे पास एक स्ट्रिंग का एक संस्करण है जो संदर्भ काउंटर को दूर करता है <> दूर काउंटर (रेट्रोएक्टिक रूप से क्लास पदानुक्रम में कुछ परिवर्तन करने योग्य नहीं है), और - लो और निहारना - आप स्वतंत्र रूप से सेमीस्ट्रीमिंग को कास्ट संदर्भ के रूप में पास कर सकते हैं, और बिना किसी लीक या मुद्दों के, दिन भर के गहरे कार्यों में उनकी नकल बनाते हैं।

चूँकि C ++ यहाँ कोई "व्युत्पन्न वर्ग कास्ट ग्रैन्युलैरिटी" प्रदान नहीं करता है, एक अच्छा विनिर्देशन लिख रहा है और एक चमकदार नया "कॉन्स्टेबल चल स्ट्रिंग" (cmstring) ऑब्जेक्ट सबसे अच्छा समाधान है जो मैंने देखा है।


@BenVoigt हां ... दूर की कास्टिंग करने के बजाय, यह परिवर्तनशील होना चाहिए ... लेकिन आप एक STL सदस्य को एक व्युत्पन्न वर्ग में उत्परिवर्तित करने के लिए नहीं बदल सकते।
एरिक एरोनिटी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.