2011-04-20 18 views
9

मेरे कोड इस तरह है:संशोधन करना एक C++ स्ट्रिंग वस्तु की मूल चार सरणी


    string s="abc"; 
    char* pc = const_cast<char*>(s.c_str()); 
    pc[1]='x'; 
    cout << s << endl; 

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

एफवाईआई, मेरा इरादा कुछ शुद्ध सी कार्यों को लिखना है जिन्हें सी और सी ++ दोनों कहा जा सकता है, इसलिए वे केवल char * को तर्क के रूप में स्वीकार कर सकते हैं। Char * से स्ट्रिंग तक, मुझे पता है कि इसमें प्रतिलिपि बनाने की प्रतिलिपि है, जुर्माना प्रतिकूल है। तो, क्या कोई इस तरह की स्थिति से निपटने के लिए कुछ सुझाव दे सकता है।

उत्तर

1

यह अपरिभाषित व्यवहार पर निर्भर है, और इसलिए पोर्टेबल नहीं है।

0

आपको अंतर्निहित स्ट्रिंग के साथ गड़बड़ नहीं करनी चाहिए। दिन के अंत में, स्ट्रिंग एक वस्तु है, क्या आप इस तरह किसी अन्य वस्तु के साथ गड़बड़ करेंगे?

क्या आपने यह जुर्माना लगाया है कि क्या जुर्माना है या नहीं।

4

(ए) यह आवश्यक अंतर्निहित स्ट्रिंग नहीं है। std::string::c_str() अंतर्निहित स्ट्रिंग की एक प्रति होना चाहिए (हालांकि सी ++ मानक में एक बग का अर्थ है कि, वास्तव में, यह अक्सर नहीं होता है ... मुझे विश्वास है कि यह सी ++ 0x में तय है)।

(ख) const_cast constness दूर ing केवल हैक करता चर के प्रकार: वास्तविक वस्तु अभी भी const है, और अपने यह अपरिभाषित व्यवहार — बहुत खराब है संशोधित।

बस बोलते हुए, ऐसा करें।


क्या आप &myString[0] का उपयोग कर सकते हैं? इसमें एक गैर-कॉन्स संस्करण है; फिर फिर, यह data()[0] जैसा ही कहा गया है जिसमें कोई गैर-कॉन्स्ट संस्करण नहीं है। किसी सभ्य पुस्तकालय के संदर्भ में कोई व्यक्ति इसे साफ़ कर सकता है।

+0

तो, सुरक्षित और आसान है [0] सुरक्षित तरीका? – Need4Steed

+0

@ Need4Steed: क्रमबद्ध करें। सी ++ 98/सी ++ 03 में, स्ट्रिंग सामग्री को तकनीकी रूप से संगत होने की गारंटी नहीं दी जाती है ... हालांकि, मानक में एक बग का मतलब है कि सभी मुख्यधारा के कार्यान्वयन _do_ इसे किसी भी तरह से संगत बनाते हैं, और इसे सी में मानक बनाया गया था ++ 0x। (सावधान रहें कि आपके द्वारा प्राप्त सूचक _not_ को शून्य-समाप्ति वाले चार सरणी पर इंगित करता है, इसलिए आपको भी लंबाई को पारित करना होगा।) –

+0

हां, नवीनतम मानकों के साथ। और वहां कोई ज्ञात कार्यान्वयन नहीं है जहां यह नहीं है। हालांकि आरक्षित लंबाई को खत्म नहीं करने के लिए सावधान रहें। – Coder

1

यह आपके ऑपरेटिंग सिस्टम पर निर्भर करेगा। जीएनयू libc लाइब्रेरी में, std::stringcopy-on-write (CoW) pattern का उपयोग करके लागू किया गया है। इस प्रकार, यदि एकाधिक std::string ऑब्जेक्ट्स में प्रारंभिक रूप से एक ही सामग्री होती है, तो वे आंतरिक रूप से सभी एक ही डेटा पर इंगित करेंगे। इस प्रकार, यदि आप अपने प्रश्न में दिखाए गए तरीके में उनमें से किसी एक को संशोधित करते हैं, तो सभी (प्रतीत होता है) असंबद्ध std::string ऑब्जेक्ट्स की सामग्री बदलेगी।

विंडोज़ पर, मुझे लगता है कि कार्यान्वयन CoW का उपयोग नहीं करता है, मुझे यकीन नहीं है कि वहां क्या होगा।

वैसे भी, यह अपरिभाषित व्यवहार है, इसलिए मैं इसके बारे में स्पष्ट रहूंगा। संभावना है, भले ही आप इसे काम कर रहे हों, फिर भी आप अंततः बहुत कठिन-टू-ट्रेस बग में चलना शुरू कर देंगे।

4

पहले भाग में, c_str()const char* देता है और इसका अर्थ यह है कि यह क्या कहता है। इस मामले में सभी const_cast प्राप्त होते हैं कि आपका अपरिभाषित व्यवहार संकलित करता है।

दूसरे भाग में, सी ++ 0x std::string में सी ++ 03 में std::vector जैसे संगत भंडारण की गारंटी है। इसलिए जब तक स्ट्रिंग खाली नहीं होती है, तब तक आप अपने कार्यों को पार करने के लिए char* प्राप्त करने के लिए &s[0] का उपयोग कर सकते हैं।व्यावहारिक रूप से, सक्रिय विकास में वर्तमान में सभी string कार्यान्वयन में पहले से ही संगत भंडारण है: मानक समिति की बैठक में एक भूसे का चुनाव था और किसी ने भी प्रतिवाद नहीं दिया। तो यदि आप चाहें तो अब आप इस सुविधा का उपयोग कर सकते हैं।

हालांकि, std::string सी शैली तार से एक मौलिक रूप से अलग स्ट्रिंग स्वरूप का उपयोग करता है, अर्थात् यह डेटा + लंबाई के बजाय नुल-समाप्त है। यदि आप अपने सी फ़ंक्शंस से स्ट्रिंग डेटा को संशोधित करते हैं, तो आप स्ट्रिंग की लंबाई नहीं बदल सकते हैं और आप सुनिश्चित नहीं कर सकते कि c_str() के बिना अंत में एक नल बाइट है। और std::string में एम्बेडेड नल शामिल हो सकते हैं जो डेटा का हिस्सा हैं, इसलिए यदि आपको लंबाई जानने के बिना एक नल मिला, तो भी आपको पता नहीं है कि आपको स्ट्रिंग का अंत मिल गया है। आप बहुत सीमित हैं जो आप उन कार्यों में कर सकते हैं जो विभिन्न प्रकार के डेटा दोनों पर सही ढंग से काम करेंगे।

2

जैसा कि अन्य ने कहा, यह पोर्टेबल नहीं है। लेकिन और अधिक खतरे हैं। कुछ std :: स्ट्रिंग कार्यान्वयन (मुझे पता है कि जीसीसी इसे करता है) गाय का उपयोग करें (लिखने पर प्रतिलिपि)।

#include <iostream> 
#include <string> 

int main() 
{ 

    std::string x("abc"); 
    std::string y; 
    y = x; // x and y share the same buffer 

    std::cout << (void*)&x[0] << '\n'; 
    std::cout << (void*)&y[0] << '\n'; 

    x[0] = 'A'; // COW triggered 

    // x and y no longer share the same buffer 
    std::cout << (void*)&x[0] << '\n'; 
    std::cout << (void*)&y[0] << '\n'; 

    return 0; 
} 
+0

सभी 'std :: स्ट्रिंग का उपयोग प्रति-लिखने वाले अर्थशास्त्र नहीं। जब आप 'std :: string' की प्रतिलिपि बनाते हैं तो कुछ कार्यान्वयन अंतर्निहित वर्ण सरणी की गहरी प्रतिलिपि बनाते हैं। किसी भी मामले में, किसी को इस तरह के कार्यान्वयन विवरण पर भरोसा नहीं करना चाहिए। –

+0

@ सिलिको में। का उल्लेख किया। धन्यवाद। – pic11

+1

मैं बफर को अन-साझा करने के लिए पहले 'और x [0]' की अपेक्षा करता हूं, क्योंकि यह नहीं बता सकता कि मैं सूचक को संग्रहीत करता हूं और बाद में इसे 'char * p = &x[0]; ... का उपयोग करता हूं; * पी = 'एक्स'; 'वाई [0] 'अब क्या है? –

1

स्पष्ट उत्तर नहीं है, यह अपरिभाषित व्यवहार है। अन्य ओर, यदि आप ऐसा करेंगे:

char* pc = &s[0]; 

आप अंतर्निहित डेटा, व्यवहार में आज तक पहुँच सकते हैं, और सी ++ 11 में गारंटी।

संबंधित मुद्दे