char * बनाम std :: c ++ में स्ट्रिंग [बंद]


81

C ++ में s के सरणियों को प्रबंधित std::stringकरने के char*लिए मुझे कब उपयोग करना चाहिए और कब करना चाहिए char?

ऐसा लगता है कि आपको उपयोग करना चाहिए char*अगर प्रदर्शन (गति) महत्वपूर्ण है और आप स्मृति प्रबंधन के कारण कुछ जोखिम भरा व्यवसाय स्वीकार करने के लिए तैयार हैं।

क्या विचार करने के लिए अन्य परिदृश्य हैं?

जवाबों:


56

यदि आप प्रतिलिपि से बचने के लिए बड़े हैं, या उदाहरण के लिए एक पॉइंटर, तो आप संदर्भ द्वारा std :: strings पास कर सकते हैं, इसलिए मुझे char संकेत का उपयोग करके कोई वास्तविक लाभ दिखाई नहीं देता है।

मैं std :: string / wstring का उपयोग कमोबेश हर चीज के लिए करता हूं जो वास्तविक टेक्स्ट है। char *हालांकि अन्य प्रकार के डेटा के लिए उपयोगी है और आप यह सुनिश्चित कर सकते हैं कि इसे वैसे ही निपटाया जाए जैसे यह होना चाहिए। अन्यथा std :: वेक्टर जाने का रास्ता है।

इस सब के लिए शायद अपवाद हैं।


8
क्या दोनों से पहले कोई प्रदर्शन अंतर है?
vtd-xml- लेखक

3
@ vtd-xml-लेखक: कुछ शायद। सीधे char *लगभग कोई उपरि नहीं है। वास्तव में जो ओवरहेड std::stringमेरे पास नहीं है, वह कार्यान्वयन पर निर्भर होने की संभावना है। मैं शायद ही ओवरहेड को नंगे चार पॉइंटर की तुलना में बहुत अधिक होने की उम्मीद करता हूं। चूंकि मैं मानक की एक प्रति का स्वामी नहीं हूं, मैं वास्तव में मानक द्वारा की गई किसी भी गारंटी का विस्तार नहीं कर सकता। किए जाने वाले संचालन के आधार पर किसी भी प्रदर्शन अंतर में भिन्नता होगी। std::string::sizeचरित्र डेटा के बगल में आकार संग्रहीत कर सकता है और इस प्रकार से अधिक तेज़ हो सकता है strlen
Skurmedel

2
गैर-पाठ डेटा के लिए std :: string का उपयोग क्यों नहीं किया जाता है? वे शून्य से समाप्त नहीं हुए हैं, इसलिए आपको वहां कुछ भी स्टोर करने में सक्षम होना चाहिए।
केसी रोडरमोर

1
@rodarmor आप अपनी इच्छानुसार कुछ भी स्टोर कर सकते हैं, हालांकि यह एक टच रिस्की है क्योंकि स्ट्रिंग को नल-टर्मिनेटेड कैरेक्टर स्ट्रिंग्स के लिए डिज़ाइन किया गया है। आपको केवल बाइनरी-सुरक्षित संचालन का उपयोग करने के लिए सावधान रहना चाहिए, जैसे append(const string&)और append(const char*, size_t)इसके बजाय operator+=()
ब्वॉयसी

6
क्या आपको यकीन है? मुझे पता है कि कई ऑपरेशन यह मान लेंगे कि एक चार * एक अशक्त समाप्त स्ट्रिंग है, लेकिन मैं किसी के बारे में सोच भी नहीं सकता कि मान लें कि एक std :: string में कोई नल नहीं है।
केसी रोडर्मर

58

मेरा नज़रिया है:

  • यदि आप "C" कोड नहीं कहते हैं तो कभी भी char * का प्रयोग न करें।
  • हमेशा std :: string का उपयोग करें: यह आसान है, यह अधिक अनुकूल है, यह अनुकूलित है, यह मानक है, यह आपको कीड़े होने से रोकेगा, इसकी जाँच की गई है और काम करने के लिए सिद्ध किया गया है।

13

कच्चे स्ट्रिंग का उपयोग

हां, कभी-कभी आप वास्तव में ऐसा कर सकते हैं। कास्ट चार * का उपयोग करते समय, स्टैक और स्ट्रिंग शाब्दिक पर आवंटित चार सरणियाँ आप इसे इस तरह से कर सकते हैं कि कोई स्मृति आवंटन नहीं है।

इस तरह के कोड को लिखने के लिए अक्सर स्ट्रिंग या वेक्टर का उपयोग करने की तुलना में अधिक सोच और देखभाल की आवश्यकता होती है, लेकिन एक उचित तकनीकों के साथ यह किया जा सकता है। उचित तकनीकों के साथ कोड सुरक्षित हो सकता है, लेकिन आपको हमेशा यह सुनिश्चित करने की आवश्यकता होती है कि चार में नकल करते समय [] या तो आपके पास नकल की जा रही स्ट्रिंग की कुछ गारंटी है, या आप जांचते हैं और सुशोभित तार को सावधानी से संभालते हैं। ऐसा नहीं करने से क्या कार्य करने वाले परिवार को असुरक्षित होने की प्रतिष्ठा मिली।

कैसे टेम्पलेट सुरक्षित चार बफ़र्स लिखने में मदद कर सकते हैं

चेर [] बफ़र सुरक्षा के लिए, टेम्पलेट मदद कर सकते हैं, क्योंकि वे आपके लिए बफर आकार को संभालने के लिए एक एनकैप्सुलेशन बना सकते हैं। इस तरह के टेम्प्लेट Microsoft द्वारा लागू किए जाते हैं जैसे कि strcpy के लिए सुरक्षित प्रतिस्थापन प्रदान करने के लिए। यहाँ उदाहरण मेरे अपने कोड से निकाला गया है, असली कोड में बहुत अधिक विधियाँ हैं, लेकिन मूल विचार को व्यक्त करने के लिए यह पर्याप्त होना चाहिए:

template <int Size>
class BString
{
  char _data[Size];

  public:
  BString()
  {
    _data[0]=0;
    // note: last character will always stay zero
    // if not, overflow occurred
    // all constructors should contain last element initialization
    // so that it can be verified during destruction
    _data[Size-1]=0;
  }
  const BString &operator = (const char *src)
  {
    strncpy(_data,src,Size-1);
    return *this;
  }

  operator const char *() const {return _data;}
};

//! overloads that make conversion of C code easier 
template <int Size>
inline const BString<Size> & strcpy(BString<Size> &dst, const char *src)
{
  return dst = src;
}

1
+1 के लिए "जब कास्ट चार * का उपयोग करते हैं, तो स्टैक और स्ट्रिंग शाब्दिक पर आवंटित चार सरणियों को आप इस तरह से कर सकते हैं कि कोई मेमोरी आवंटन बिल्कुल भी न हो।" लोग भूल जाते हैं कि ढेर "आवंटन" ढेर की तुलना में बहुत तेज है।
NoSenseEtAl

char*तार हमेशा स्टैक पर नहीं होते हैं। char *str = (char*)malloc(1024); str[1024] = 0;
कोल जॉनसन

@ColeJohnson मैं यह दावा नहीं कर रहा हूं कि, मेरा तात्पर्य यह है कि यदि आप चाहते हैं कि आपका स्ट्रिंग स्टैक आवंटित किया जाए, तो आपको स्ट्रिंग शाब्दिकों के साथ संयोजन में कॉन्स्टर्ड चार का उपयोग करना होगा, न कि std :: string का।
सूमा

9

जब आप स्थैतिक स्ट्रिंग स्थिरांक की आवश्यकता होती है तो एक अवसर जिसका आप उपयोग करते हैं char*और नहीं std::stringकरते हैं। इसका कारण यह है कि आपके पास अपने स्थैतिक चर को इनिशियलाइज़ करने के लिए ऑर्डर मॉड्यूल पर कोई नियंत्रण नहीं होता है, और एक अलग मॉड्यूल से एक और वैश्विक ऑब्जेक्ट आपके स्ट्रिंग को संदर्भित कर सकता है, इससे पहले कि यह प्रारंभ हो जाए। http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Static_and_Global_Variables

std::string पेशेवरों:

  • आपके लिए मेमोरी का प्रबंधन करता है (स्ट्रिंग बढ़ सकता है, और कार्यान्वयन आपको एक बड़ा बफर आवंटित करेगा)
  • उच्च-स्तरीय प्रोग्रामिंग इंटरफ़ेस, बाकी एसटीएल के साथ अच्छी तरह से काम करता है।

std::stringविपक्ष: - दो अलग एसटीएल स्ट्रिंग उदाहरण एक ही अंतर्निहित बफर को साझा नहीं कर सकते हैं। इसलिए यदि आप मूल्य से गुजरते हैं तो आपको हमेशा एक नई प्रति मिलती है। - कुछ प्रदर्शन जुर्माना है, लेकिन मैं कहूंगा कि जब तक आपकी आवश्यकताएं विशेष नहीं हैं, यह नगण्य है।


दरअसल, एसटीएल कार्यान्वयन अक्सर std :: string के लिए कॉपी-ऑन-राइट सेमेंटिक्स को लागू करते हैं, इसलिए मूल्य द्वारा उन्हें पास करना बहुत ज्यादा खर्च नहीं होता है। फिर भी, उस पर भरोसा नहीं करना बेहतर है, और आम तौर पर किसी भी तरह एक संदर्भ-से-पास पारित करना बेहतर है।

1
कुछ एसटीडी :: स्ट्रिंग कार्यान्वयन ने गाय कार्यान्वयन पर छोड़ दिया। इसके अलावा यह उतना तुच्छ नहीं है क्योंकि यह मानक के साथ संगत एक (POSIX) धागा सुरक्षित वर्ग प्रदान करता है। देखें groups.google.fr/group/ifi.test.boa/browse_frm/thread/... या groups.google.fr/group/comp.programming.threads/browse_frm/...
ल्यूक Hermitte

8

आपको char*निम्नलिखित मामलों में उपयोग करने पर विचार करना चाहिए :

  • यह सरणी पैरामीटर में पारित की जाएगी।
  • आप अपने सरणी के अधिकतम आकार को पहले से जानते हैं (आप इसे जानते हैं या आप इसे लागू करते हैं)।
  • आप इस सरणी पर कोई परिवर्तन नहीं करेंगे।

वास्तव में, C ++ में, char*अक्सर निश्चित छोटे शब्द के लिए उपयोग किया जाता है, विकल्प, फ़ाइल नाम, आदि के रूप में ...


3
सरणी पारित नहीं है, सरणी के लिए एक सूचक है। यही एक सूचक है - किसी वस्तु का सूचक।
कोल जॉनसन

5

C ++ std :: string का उपयोग कब करें:

  • तार, कुल मिलाकर, चार * की तुलना में अधिक सुरक्षित हैं, आम तौर पर जब आप चार के साथ चीजें कर रहे हैं * तो आपको यह सुनिश्चित करने के लिए चीजों को जांचना होगा कि चीजें सही हैं, स्ट्रिंग कक्षा में यह सब आपके लिए किया जाता है।
  • आमतौर पर चार * का उपयोग करते समय, आपको अपने द्वारा आवंटित मेमोरी को मुक्त करना होगा, आपको स्ट्रिंग के साथ ऐसा करने की आवश्यकता नहीं है क्योंकि यह अपने आंतरिक बफर को तबाह कर देगा।
  • स्ट्रिंग्स c ++ स्ट्रिंगस्ट्रीम के साथ अच्छी तरह से काम करते हैं, स्वरूपित IO बहुत आसान है।

चार का उपयोग कब करें *

  • चार का उपयोग करना आपको दृश्यों के "पीछे" होने पर अधिक नियंत्रण प्रदान करता है, जिसका अर्थ है कि यदि आपको ज़रूरत है तो आप प्रदर्शन को ट्यून कर सकते हैं।

3

यदि आप लाइब्रेरी लिख रहे हैं तो (const) char * को पैरामीटर के रूप में उपयोग करें। std :: स्ट्रिंग कार्यान्वयन अलग-अलग संकलक के बीच भिन्न होते हैं।


यदि आप C ++ में लाइब्रेरी लिख रहे हैं, तो std :: string का लेआउट एकमात्र ऐसी चीज नहीं है जिसके बारे में आपको चिंता करनी है। दो कार्यान्वयन के बीच संभावित असंगतियों के मेजबान हैं। C ++ में पुस्तकालयों का उपयोग केवल तभी करें जब आपके द्वारा उपयोग किए जा रहे सटीक कंपाइलर के लिए स्रोत या संकलित में उपलब्ध हो। C लाइब्रेरी आमतौर पर अधिक पोर्टेबल होती हैं, लेकिन उस स्थिति में आपके पास वैसे भी std :: string नहीं है।
डेविड थॉर्नले

यह सच है कि std :: string एकमात्र समस्या नहीं है, लेकिन यह निष्कर्ष निकालने के लिए बहुत अधिक है "केवल C ++ में पुस्तकालयों का उपयोग करें यदि स्रोत में उपलब्ध है या आपके द्वारा उपयोग किए जा रहे सटीक कंपाइलर के लिए संकलित किया गया है।" ऐसे घटक सिस्टम हैं जो विभिन्न संकलक (COM, उदाहरण के लिए) के साथ ठीक काम करते हैं और यह संभव है कि C इंटरफ़ेस को एक लाइब्रेरी में उजागर किया जाए, जिसे आंतरिक रूप से C ++ (Win32 API, उदाहरण के लिए) के साथ लिखा गया हो
Nemanja Trifunovic

2

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


2

आप एक std :: string (जैसे जैसे find) पर अधिकांश ऑपरेशनों को यथासंभव अनुकूलित करने की अपेक्षा कर सकते हैं, इसलिए वे कम से कम और साथ ही एक शुद्ध C समकक्ष प्रदर्शन करने की संभावना रखते हैं।

यह भी ध्यान देने योग्य बात है कि std :: string iterators, अक्सर चार्ट में अंतर्निहित चार्ट में मैप करते हैं। तो किसी भी एल्गोरिथ्म जो आप पुनरावृत्तियों के शीर्ष पर है, अनिवार्य रूप से प्रदर्शन के मामले में चार के शीर्ष पर समान एल्गोरिथ्म के समान है।

देखने के लिए चीजें उदाहरण के लिए हैं operator[]- अधिकांश एसटीएल कार्यान्वयन सीमा की जाँच नहीं करते हैं, और इसे अंतर्निहित वर्ण सरणी पर उसी ऑपरेशन में अनुवाद करना चाहिए। AFAIK STLPort वैकल्पिक रूप से सीमा जाँच कर सकती है, जिस बिंदु पर यह ऑपरेटर थोड़ा धीमा होगा।

तो क्या करता है std :: string आपको फायदा करती है? यह आपको मैनुअल मेमोरी प्रबंधन से अनुपस्थित करता है; सरणी का आकार बदलना आसान हो जाता है, और आपको आम तौर पर मुक्त स्मृति के बारे में कम सोचना पड़ता है।

यदि आप स्ट्रिंग का आकार बदलते समय प्रदर्शन के बारे में चिंतित हैं, तो एक reserveफ़ंक्शन है जो आपको उपयोगी मिल सकता है।


1

अगर आप टेक्स्ट आदि जैसे वर्णों का उपयोग कर रहे हैं, तो std :: string का उपयोग अधिक लचीला और प्रयोग करने में आसान है। अगर आप इसका इस्तेमाल डाटा स्टोरेज जैसी किसी और चीज के लिए करते हैं? सरणियों का उपयोग करें (वैक्टर को प्राथमिकता दें)


1

यहां तक ​​कि जब प्रदर्शन महत्वपूर्ण होता है तो आप बेहतर उपयोग करते हैं vector<char>- यह अग्रिम (रिजर्व () विधि) में मेमोरी आवंटन की अनुमति देता है और आपको मेमोरी लीक से बचने में मदद करेगा। वेक्टर का उपयोग :: ऑपरेटर [] एक ओवरहेड की ओर जाता है, लेकिन आप हमेशा बफर के पते को निकाल सकते हैं और इसे ठीक उसी तरह अनुक्रमित कर सकते हैं जैसे कि यह एक चार * था।


लेकिन कुछ प्रकार की विशिष्ट स्ट्रिंग कार्यक्षमता का उपयोग करना अच्छा होगा, और भंडारण के लिए पॉलिसी को निर्दिष्ट करने का सिर्फ एक विकल्प है। उसके लिए मेरे उत्तर में लिंक देखें।
बेनामी

यह वास्तविक नहीं है। यदि आप समझते हैं कि वेक्टर को सन्निहित मेमोरी स्पेस में आवंटित किया जाएगा, तो रियलाइकेशन (वेक्टर आकार बढ़ाने के लिए) बिल्कुल भी कुशल नहीं होगा, क्योंकि यह पिछले चंक की कॉपी का अर्थ है।
7:27 पर Jérôme

मैं आपकी प्रतिक्रिया को गलत समझता हूं, जैसा कि आप char * के बजाय वेक्टर का उपयोग करते हैं, स्ट्रिंग के बजाय ... इस मामले में मैं सहमत हूं।
Jérôme

ऑपरेटर [] उपयोग में ओवरहेड नहीं होना चाहिए। उदाहरण के लिए देखें, stackoverflow.com/questions/381621/…
Luc Hermitte

-1

AFAIK आंतरिक रूप से सबसे std :: स्ट्रिंग को कॉपी पर लिखें, संदर्भ को ओवरहेड से बचने के लिए शब्दार्थ गिना जाता है, भले ही तार संदर्भ से पारित न हों।


5
यह अब सच नहीं है, क्योंकि लेखन पर कॉपी मल्टीथ्रेडेड वातावरण में गंभीर स्केलेबिलिटी मुद्दों का कारण बनती है।
सुमा

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