2009-04-01 11 views
13

एसटीएल मानक को std :: स्ट्रिंग से refcounted करने की आवश्यकता नहीं है। लेकिन वास्तव में सी ++ कार्यान्वयन के अधिकांश पुनर्नवीनीकरण, कॉपी-ऑन-राइट स्ट्रिंग प्रदान करते हैं, जिससे आप स्ट्रिंग को मूल प्रकार के रूप में मानते हैं। इन कार्यान्वयन (कम से कम जी ++) परमाणु संचालन का उपयोग करते हैं जो इन स्ट्रिंग लॉक-फ्री और थ्रेड सुरक्षित बनाते हैं।वीसी ++ स्ट्रिंग्स का संदर्भ क्यों नहीं दिया जाता है?

आसान परीक्षण कॉपी-ऑन-राइट सीमेंटिक्स पता चलता है:

#include <iostream> 
#include <string> 

using namespace std; 

void foo(string s) 
{ 
    cout<<(void*)s.c_str()<<endl; 
    string ss=s; 
    cout<<(void*)ss.c_str()<<endl; 
    char p=ss[0]; 
    cout<<(void*)ss.c_str()<<endl; 
} 

int main() 
{ 
    string s="coocko"; 
    cout<<(void*)s.c_str()<<endl; 
    foo(s); 
    cout<<(void*)s.c_str()<<endl; 
} 

केवल दो adresses मुद्रित कर रहे हैं वास्तव में के बाद एक गैर निरंतर सदस्य इस्तेमाल किया गया था।

मैंने एचपी, जीसीसी और इंटेल कंपाइलर का उपयोग करके इस कोड का परीक्षण किया और इसी तरह के परिणाम प्राप्त किए - स्ट्रिंग्स कॉपी-ऑन-राइट कंटेनर के रूप में काम करते हैं।

दूसरी ओर, वीसी ++ 2005 स्पष्ट रूप से दिखाता है कि प्रत्येक स्ट्रिंग पूरी तरह से कॉपी की जाती है।

क्यों?

मुझे पता है कि वीसी ++ 6.0 में एक बग था जिसमें संदर्भ गिनती के गैर-थ्रेड-सुरक्षित कार्यान्वयन था जो यादृच्छिक कार्यक्रम के कारण बनता था। क्या यही कारण है? वे सिर्फ रेफ-गिनती का उपयोग करने से डरते हैं, फिर भी यह सामान्य अभ्यास है? वे इस मुद्दे को ठीक करने के लिए रीफ-गिनती का उपयोग नहीं करना पसंद करते हैं?

धन्यवाद

उत्तर

22

मुझे लगता है कि अधिक से अधिक std::string कार्यान्वयन/refcounting से दूर चले जाएँगे कॉपी-ऑन-राइट के रूप में यह अक्सर मल्टी-थ्रेडेड कोड में एक जवाबी अनुकूलन है।

हर्ब सटर के लेख Optimizations That Aren't (In a Multithreaded World) देखें।

+0

मुझे विश्वास है कि स्कॉट Meyers अपनी पुस्तकों में से एक में कुछ इसी तरह का उल्लेख है - अदालत में तलब नहीं कर सकते (और यहां तक ​​यकीन नहीं), क्योंकि मैं पर मेरे साथ उन्हें जरूरत नहीं है पल। –

+2

+1, उस संदर्भ को देखने में 10 मिनट बिताए। एसओ पर इतने सारे सी ++ प्रश्न हैं जिन्हें हर्ब के लेखन के लिए केवल एक सूचक की आवश्यकता होती है। – JaredPar

+2

वास्तव में यह आलेख स्पष्ट रूप से दिखाता है कि परमाणु संचालन का उपयोग कर गाय स्ट्रिंग सामान्य गाय स्ट्रिंग के समान प्रदर्शन करते हैं। (25% का अंतर) तो यह बहुत अधिक "ओवरहेड" नहीं है, और वास्तविक प्रतिलिपि करने के लिए बदनाम रूप से बहुत कुछ है। – Artyom

5

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

या शायद नहीं। यदि यह आपके लिए चिंता का विषय है, तो आपको यह निर्धारित करने के लिए अपने आवेदन को प्रोफ़ाइल करना चाहिए कि क्या स्ट्रिंग प्रतिलिपि एक प्रमुख ओवरहेड है, और यदि यह एक अलग स्ट्रिंग कार्यान्वयन पर स्विच है।

+1

हाँ मैं सहमत हूं। जेएसयूटी रेफरी द्वारा पास क्या बड़ी बात है? टाइपिंग पर सहेजना चाहते हैं? –

1

यह मुख्य कारण नहीं है, लेकिन मैंने Win32 प्लेटफॉर्म के तहत बहुत सी गलत कोड देखा जो const_cast< char* >(str.c_str()) जैसा कुछ करता है।

हो सकता है कि माइक्रोसॉफ्ट इस जानते हैं और आवश्यकता के बारे में डेवलपर्स :)

+0

मैंने पहले यह नहीं सुना था, लेकिन मैं शर्त लगाऊंगा कि आप सही हैं कि यह एक कारक हो सकता है। –

11

एसटीएल वास्तविक ख्याल रखता है कि आप गिनती कि अर्थ विज्ञान एक गैर संदर्भ गिना संस्करण के लिए जैसे ही हैं संदर्भ का उपयोग करते हैं। यह सामान्य मामले के लिए तुच्छ नहीं है। (यही कारण है कि आपको अपनी स्ट्रिंग क्लास पर नहीं लिखना चाहिए)।

निम्नलिखित स्थिति की वजह से

:

std::string x("This is a string"); 
char&   x5 = x[5]; 
std::string y(x); 

x5 = '*'; 

देखें: अधिक जानकारी के

+0

दिलचस्प ... मानक वास्तव में एक नोट है जो विशेष रूप से कहता है कि refcounted स्ट्रिंग की अनुमति है, लेकिन sematics गैर-refcounted तारों के समान होना चाहिए। (आकार सीमाओं के कारण अगली टिप्पणी में टिप्पणी जारी रही) –

+0

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

+0

-1 आप वास्तव में इस कोड को g ++ में देख सकते हैं और देख सकते हैं कि यह पूरी तरह से काम करता है। वास्तव में जी ++ में रेफ-गिनती का उपयोग करके थ्रेड सुरक्षित तार होते हैं। तो यह अपमानजनक रूप से करने योग्य है – Artyom

7

के लिए http://www.sgi.com/tech/stl/string_discussion.html, मार्टिन & माइकल द्वारा कहा गया है लिखें (गाय) पर कॉपी अक्सर अधिक परेशानी की तुलना में यह लायक है, आगे के लिए है केल्विन हेनी के बारे में इस उत्कृष्ट आलेख को पढ़ने के बारे में Mad COW Disease और मेरा मानना ​​है कि यह आंद्रेई अलेक्जेंड्रेस्कू ने कहा कि छोटे स्ट्रिंग अनुकूलन कई अनुप्रयोगों में बेहतर प्रदर्शन करता है (लेकिन मुझे लेख नहीं मिल रहा है)।

छोटे स्ट्रिंग अनुकूलन वह जगह है जहां आप स्ट्रिंग ऑब्जेक्ट को बड़ा बनाते हैं और छोटे तारों के लिए ढेर आवंटन से बचते हैं। एक खिलौना कार्यान्वयन कुछ इस तरह दिखेगा:

class string { 
    char *begin_, *end_, *capacity_; 
    char buff_[64]; // pick optimal size (or template argument) 
public: 
    string(const char* str) 
    { 
     size_t len = strlen(str); 
     if (len < sizeof(buff_)) 
     { 
      strcpy(buff_, str); 
      begin_ = buff_; 
      capacity_ = buff_ + sizeof(buff_); 
     } 
     else 
     { 
      begin_ = strdup(str); 
      capacity_ = begin_ + len; 
     } 
     end_ = begin_+len; 
    } 

    ~string() 
    { 
     if (begin_ != buff_) 
      free(begin_); // strdup requires free 
    } 
    // ... 
}; 
संबंधित मुद्दे