2012-04-24 12 views
7

यह शायद एक मूर्खतापूर्ण सवाल हो रहा है, लेकिन मैं वास्तव में इस स्पष्ट करने की आवश्यकता:सी ++ स्थिरांक डाली, अनिश्चित अगर यह सुरक्षित है

यह मेरा कार्यक्रम के लिए किसी भी खतरे लाएगा?

क्या const_cast भी आवश्यक है?

यदि मैं इनपुट पॉइंटर्स मानों को जगह में बदलता हूं तो यह std::string के साथ सुरक्षित रूप से काम करेगा या यह अपरिभाषित व्यवहार बनाएगा?

अभी तक एकमात्र चिंता यह है कि जब भी मैं इनपुट पॉइंटर को संशोधित करता हूं और इसे अनुपयोगी बनाता है तो यह "some_text" स्ट्रिंग को प्रभावित कर सकता है। मुझे कुछ संकेत देने के लिए

std::string some_text = "Text with some input"; 

char * input = const_cast<char*>(some_text.c_str()); 

धन्यवाद, मैं इसकी constness const_cast का उपयोग कर दूर कास्टिंग द्वारा अपने ही पैर

+0

आम तौर पर, चूंकि 'const_cast' सुरक्षा को हटा देता है, इसलिए आपको जितना संभव हो उतना टालना चाहिए। – Mesop

+0

हर शरीर के योगदान के लिए धन्यवाद, अब मैं समझता हूं कि मुझे सुरक्षित रहने के लिए इस से बचना चाहिए –

उत्तर

13

बुरा व्यवहार का एक उदाहरण के रूप में: जीसीसी की प्रतिलिपि लिखने पर क्रियान्वयन के साथ बातचीत।

#include <string> 
#include <iostream> 

int main() { 
    std::string const original = "Hello, World!"; 
    std::string copy = original; 

    char* c = const_cast<char*>(copy.c_str()); 
    c[0] = 'J'; 

    std::cout << original << "\n"; 
} 
कार्रवाई में ideone पर

जेलो, दुनिया!

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

अब, अपनी बुराई कार्यक्रम के साथ, आप साझा बफर एक स्थिरांक-विधि के माध्यम से पहुंच (कुछ भी संशोधित नहीं वादा किया है), लेकिन आप इसे संशोधित करते हैं!

ध्यान दें कि एमएसवीसी के कार्यान्वयन के साथ, जो प्रतिलिपि लिखने का उपयोग नहीं करता है, व्यवहार अलग होगा ("Hello, World!" सही ढंग से मुद्रित किया जाएगा)।

यह बिल्कुल अनिर्धारित व्यवहार का सार है।

+16

* अनिर्धारित व्यवहार का सार *: आपकी दुनिया _jello_ पर बदल जाती है। –

+0

इस अंतर्दृष्टि के लिए धन्यवाद –

5

एक स्वाभाविक const वस्तु को संशोधित करने के में गोली मार से बचने के लिए चाहते हैं एक अपरिभाषित व्यवहार है।

string::c_str() रिटर्न एक const char *, यानी: एक निरंतर सी शैली स्ट्रिंग के लिए एक सूचक। तकनीकी रूप से, इसे संशोधित करने के परिणामस्वरूप अपरिभाषित व्यवहार होगा।

नोट, कि const_cast का उपयोग तब होता है जब आपके पास const पॉइंटर नॉन कॉन्स्ट डेटा पर होता है और आप गैर-निरंतर डेटा को संशोधित करना चाहते हैं।

+0

मुझे एक स्ट्रिंग विकल्प नहीं मिला है जो cststr के बिना c_str() ऑपरेशन करता है, क्या कोई विकल्प पसंद किया जाता है? –

+0

यह मामला हो सकता है कि 'c_str'' char' की सरणी में पॉइंटर लौटाता है, न कि 'char char'। तो औपचारिक रूप से आप क्या कह सकते हैं कि आप यह गारंटी नहीं दे सकते कि कार्यक्रम सही है अगर यह 'इनपुट' के माध्यम से वस्तुओं को संशोधित करता है, गारंटी नहीं कि प्रोग्राम गलत है। –

+0

@OliverStutz: आपके पास एक और पर्याप्त आवंटित (सरणी या सूचक) चर स्ट्रिंग को स्ट्रिंग की प्रतिलिपि बनाना चाहिए और उसके बाद दूसरी चर में कॉपी की गई स्ट्रिंग को संशोधित करना होगा। –

1

हाँ, यह खतरा लाएगा, क्योंकि

  1. input अंक जो कुछ भी करने के लिए c_str होता है अभी होना करने के लिए, लेकिन अगर some_text कभी परिवर्तन या गायब हो जाता है, तो आप एक सूचक है कि कचरा के लिए अंक के साथ छोड़ दिया हो जाएगा । c_str का मान केवल तब तक मान्य होने की गारंटी है जब तक स्ट्रिंग नहीं बदली जाती। और यहां तक ​​कि, औपचारिक रूप से, केवल तभी यदि आप c_str() को अन्य तारों पर भी कॉल नहीं करते हैं।
  2. आपको कॉन्स को दूर करने की आवश्यकता क्यों है? आप *input पर लिखने की योजना नहीं बना रहे हैं, है ना? वह एक नहीं है!
+0

वास्तव में वही था जो मैं करना चाहता था, स्ट्रिंग को संशोधित करने के लिए (उदाहरण के लिए डुप्लिकेट वर्ण हटाएं) मेरा सबसे बड़ा मुद्दा यह था कि यह वास्तव में मुझे संकलित करने और चलाने के लिए अनुमति देता है, लेकिन वास्तव में मुझे इस पोस्ट को खोलने के लिए बनाया गया क्योंकि यह कास्ट करने के लिए अनलॉक लगता है दूर हो गया और उसके बाद मैं इसे सही ढंग से लिखने और संशोधित करने में सक्षम हूं (शायद यह पहले से ही दक्षिण में जाता है लेकिन यह मेरे लिए दृश्यमान नहीं है) –

+1

@OliverStutz डुप्लिकेट वर्णों को हटाने जैसी चीजें 'std :: string' में निर्मित करके किया जा सकता है कार्य करता है। लेकिन अगर आप पुराने सी कार्यों को बेहतर पसंद करते हैं, तो पुराने सी को सभी तरह से जाएं और पहले 'स्ट्रैपी' बनाएं! –

2

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

उस तरह से const_cast का उपयोग करके सचमुच ऐसी सुरक्षा दूर हो जाती है और केवल एक तर्कसंगत स्वीकार्य अभ्यास है यदि आप पूरी तरह से सुनिश्चित हैं कि स्मृति संशोधित नहीं की जाएगी।

यदि आप इसकी गारंटी नहीं दे सकते हैं तो आपको स्ट्रिंग की प्रतिलिपि बनाना होगा और प्रतिलिपि का उपयोग करना होगा। यह निश्चित रूप से किसी भी घटना में ऐसा करने के लिए बहुत सुरक्षित है (आप strcpy का उपयोग कर सकते हैं)।

const char* c_str () const; 

"स्ट्रिंग वस्तु के रूप में एक ही सामग्री के साथ पात्रों (ग-स्ट्रिंग) की एक अशक्त-समाप्त अनुक्रम उत्पन्न करता है और पात्रों की एक सरणी के सूचक के रूप में यह रिटर्न:

2

C++ reference वेबसाइट देखें।

एक समाप्ति शून्य वर्ण स्वचालित रूप से जोड़ा जाता है।

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

4

सीधे शब्दों में कास्टिंग आगे एक अपरिभाषित व्यवहार नहीं लाएगी।, संशोधित करना डेटा की दिशा में रखे हालांकि, होगा। (Also see ISO 14882:98 5.2.7-7)।

आप तो परिवर्तनीय डेटा के लिए सूचक चाहते हैं, आप एक

हो सकता है
+7

wtf और lol - नया foo और bar? – gwiazdorrr

+1

अब इसके अलावा, आपके पास एक निरस्त समाप्त स्ट्रिंग नहीं है। जो आपके पास 'char * c = str.c_str() के साथ नहीं है; std :: vector foo (c, c + str.size() + 1); ' – stefaanv

1

यह एक बहुत ही बुरी बात करना है। जांचें कि std :: string :: c_str() does और मुझसे सहमत हैं।

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

std::string input(some_text); 

बारे में आप, कि तुम छेड़छाड़ न कर सके मूल को प्रभावित किए बिना के साथ एक std :: स्ट्रिंग है और आप std है :: बजाय एक कच्चे सी ++ सूचक के साथ काम करने की स्ट्रिंग कार्यक्षमता ...

+0

यदि ओपी को 'char *' की आवश्यकता है, तो ऐसा करने से ऐसा कोई अच्छा नहीं है, क्योंकि आपके पास नई समस्याएं हैं मूल के साथ स्ट्रिंग! –

1

इस पर एक और स्पिन यह है कि यह कोड को बनाए रखने में बेहद मुश्किल बनाता है। मामले में मामला: कुछ साल पहले मुझे लंबे कार्यों वाले कुछ कोड को दोबारा बदलना पड़ा। लेखक ने कॉन्स्ट पैरामीटर स्वीकार करने के लिए फ़ंक्शन हस्ताक्षर लिखे थे लेकिन फिर const_cast उन्हें स्थिरता को हटाने के लिए फ़ंक्शन के भीतर आईएनजी था। इसने फ़ंक्शन द्वारा दी गई अंतर्निहित गारंटी तोड़ दी और यह जानना बहुत मुश्किल हो गया कि पैरामीटर बदल गया है या कोड के बाकी हिस्सों में नहीं है।

संक्षेप में, यदि आपके पास स्ट्रिंग पर नियंत्रण है और आपको लगता है कि आपको इसे बदलने की आवश्यकता होगी, इसे पहले स्थान पर नॉन-कॉन्स्ट बनाएं। यदि आप नहीं करते हैं तो आपको एक प्रतिलिपि लेनी होगी और उसके साथ काम करना होगा।

1

यह यूबी है। उदाहरण के लिए, आप इस कुछ इस तरह कर सकते हैं: किसी भी कास्ट और comiler एक त्रुटि रिपोर्ट नहीं करेगा बिना

size_t const size = (sizeof(int) == 4 ? 1024 : 2048); 
int arr[size]; 

। लेकिन यह कोड अवैध है। मनोबल यह है कि आपको हर बार कार्रवाई करने की आवश्यकता है।

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