2011-01-06 3 views
8

आप एक वर्ग है जो एक वैश्विक (जैसे एप्लिकेशन के क्रम के लिए उपलब्ध)कैसे ठीक से वापस जाने के लिए std :: स्ट्रिंग (या कैसे ठीक है कि दिए गए मान का उपयोग करने)

class MyClass { 
    protected: 
    std::string m_Value; 
    public: 
    MyClass() : m_Value("hello") {} 
    std::string value() { return m_Value; }  
}; 

MyClass v1; 

पहले का उपयोग करना है कहो प्रपत्र मुझे अजीब व्यवहार देता है जब मैं

printf("value: %s\n", v1.value().c_str()); 

कर ऐसा लगता है कि स्ट्रिंग के रूप में यद्यपि स्मृति से गायब हो जाता है printf से पहले इसका इस्तेमाल कर सकते हैं। कभी-कभी यह मूल्य प्रिंट करता है: हैलो अन्य बार यह क्रैश या प्रिंट नहीं करता है।

मैं पहली बार इतना

std::string copiedString = v1.value(); 
    printf("value: %s\n", copiedString.c_str()); 

चीजें काम करने की तरह स्ट्रिंग कॉपी करते हैं।

निश्चित रूप से अस्थायी स्ट्रिंग के साथ ऐसा करने से बचने का एक तरीका होना चाहिए।

संपादित करें: तो सर्वसम्मति एक कॉन्स std :: स्ट्रिंग & वापसी मूल्य के साथ जाना है।

मुझे पता है कि हर कोई कहता है कि मूल कोड ठीक होना चाहिए लेकिन मैं आपको बता सकता हूं कि मैंने विंडोज सीई पर एमएसवीसी 2005 को इसके साथ परेशानी है, लेकिन केवल सीई बॉक्स पर देखा है। Win32 क्रॉस संकलन नहीं है।

+5

क्या आप एक संकलित उदाहरण पोस्ट कर सकते हैं? ठीक है, मैं नहीं देखता कि आप क्या अनुभव कर रहे हैं। – Falmarri

+7

अस्थायी 'v1.value()' पूर्ण अभिव्यक्ति के अंत तक जीना चाहिए, यानी इसे 'printf' रिटर्न से पहले नष्ट नहीं किया जाना चाहिए। –

+0

@ चार्ल्स बेली: क्या यह वास्तव में होना चाहिए? क्या यह नियमित रूप से c_str() से नियमित char * प्राप्त करने के लिए मूल्यांकन नहीं किया गया है? – villintehaspam

उत्तर

1

ठीक है, कोड के साथ कुछ भी गलत नहीं है (जैसा कि मैंने इसे समझा है)। यह इष्टतम नहीं है और निश्चित रूप से The Right Way (R) नहीं है, आपको अपने कोड को संशोधित करना चाहिए जैसे villentehaspam सुझाव। जैसा कि अब है, आपका कोड स्ट्रिंग m_value की प्रतिलिपि बनाता है क्योंकि आप मान द्वारा वापस आते हैं, जो केवल एक कॉन्स्ट संदर्भ लौटने के समान नहीं है।

यदि आप एक पूर्ण कोड नमूना प्रदान करते हैं जो समस्या दिखाता है, तो मैं आपकी मदद कर सकता हूं।

+0

पहले से ही C++ 1x के चलने वाले अर्थशास्त्र को लागू करने वाले एक कंपाइलर के साथ संकलित करें और इस (नवीनतम वीसी और जीसीसी पर्याप्त) का एक स्टेब लिब लेने का लाभ उठाएं, और वह प्रतिलिपि बहुत सस्ते चाल में बदल दी जानी चाहिए। – sbi

+0

विंडोज सीई विकास के कारण एमएसवीसी2005 के साथ फंस गया (क्या आप मेरे बालों को भूरे रंग में देख सकते हैं?) – Ron

+0

कंपाइलर स्ट्रिंग को स्थानांतरित करने से पहले कॉपी कन्स्ट्रक्टर को पहले से जोड़ने का प्रयास करता है।AFAIK, यहां तक ​​कि पुराने वीसी2005 भी इस मामले में आसानी से ऐसा करेंगे। –

6

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

0

यह महत्वपूर्ण नहीं है कि उस वर्ग में std :: स्ट्रिंग रिटर्न एक कॉन्स का उपयोग कर सकता है और आप केवल सदस्य मूल्य की एक प्रति बना रहे हैं जो एक अपशिष्ट है।

std::string value() const { return m_value; } 
-1

यहाँ आम तौर पर हो रहा है जब आप लिखते हैं:

printf("value: %s\n", v1.value().c_str()); 
  1. संकलक v1.value() से दिए गए मान धारण करने के लिए एक अस्थायी std::string बनाता है।
  2. यह v1.value() पर कॉल करता है और अस्थायी स्ट्रिंग में अपना रिटर्न मान डालता है (वास्तव में यह कैसे भिन्न हो सकता है: आमतौर पर यह अस्थायी के लिए विधि के छिपे पैरामीटर के रूप में संदर्भित करेगा। चर्चा के लिए http://en.wikipedia.org/wiki/Return_value_optimization देखें)।
  3. यह अस्थायी std::string पर .c_str() पर कॉल करता है, यह const char * परिणाम कहीं दूर (उदाहरण के लिए एक रजिस्टर) को दबाता है।
  4. अब यह अस्थायी std::string के साथ समाप्त हो गया है, इसलिए इसे नष्ट कर देता है (यानी इसके विनाशक को कॉल करता है, शायद कुछ स्टैक स्पेस को मुक्त कर सकता है)।
  5. यह const char * पॉइंटर को printf() पर तर्क के रूप में चरण (3) में मिला है।

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

असल में, आपके द्वारा दिखाए गए किसी भी उपयोग को खतरनाक है और इससे बचा जाना चाहिए। निम्नलिखित का उपयोग करना सही है:

std::string copiedString = v1.value(); 
printf("value: %s\n", copiedString.c_str()); 

क्योंकि copiedString के लिए नाशक तक copiedString दायरे से बाहर चला जाता है कहा जाता है नहीं होता है, printf() के कुछ समय बाद वापस आ गया है। वास्तव में, यह v1.value().c_str() से कम कुशल नहीं है, क्योंकि किसी भी मामले में अस्थायी std::string बनाया जाता है।

एक स्ट्रिंग का संदर्भ लौटने का एक अच्छा विकल्प है, प्रदान किया गया है कि संदर्भ तब तक मान्य रहता है जब तक कॉलर को इसकी आवश्यकता होती है। इसलिए, एक दीर्घकालिक वस्तु में एक सदस्य चर के संदर्भ ठीक है; कुछ ऐसा संदर्भ जो अस्थायी साबित होता है वह नहीं है।

+0

चरण 4 चरण 5 के बाद होता है, अस्थायी पूर्ण अभिव्यक्ति के अंत तक रहते हैं। – MSalters

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