2012-03-05 13 views
15

मैं उदाहरण से शुरू करूंगा। बूस्ट में एक अच्छा "टोकनाइज़र" वर्ग है। यह एक स्ट्रिंग ले एक निर्माता में पैरामीटर के रूप tokenized जा करने के लिए:किसी कन्स्ट्रक्टर में मौजूदा ऑब्जेक्ट के पॉइंटर/संदर्भ को पारित करने का पसंदीदा तरीका क्या है?

std::string string_to_tokenize("a bb ccc ddd 0"); 
boost::tokenizer<boost::char_separator<char> > my_tok(string_to_tokenize); 
/* do something with my_tok */ 

स्ट्रिंग tokenizer में modifed नहीं है, तो यह स्थिरांक वस्तु संदर्भ द्वारा पारित कर दिया है। इसलिए मैं एक अस्थायी वस्तु वहाँ पारित कर सकते हैं:

boost::tokenizer<boost::char_separator<char> > my_tok(std::string("a bb ccc ddd 0")); 
/* do something with my_tok */ 

सब कुछ ठीक लग रहा है, लेकिन अगर मैं tokenizer इस्तेमाल करने की कोशिश, एक आपदा होता है। छोटी जांच के बाद मुझे एहसास हुआ कि टोकननाइज़र क्लास उस संदर्भ को संग्रहीत करता है जिसे मैंने दिया है, और आगे के उपयोग में उपयोग करें। बेशक यह अस्थायी वस्तु के संदर्भ के लिए अच्छी तरह से काम नहीं कर सकता है।

प्रलेखन स्पष्ट रूप से यह नहीं कहता कि कन्स्ट्रक्टर में पारित वस्तु का उपयोग बाद में किया जाएगा, लेकिन ठीक है, यह भी नहीं कहा गया है कि यह नहीं होगा :) तो मैं यह नहीं मान सकता, मेरी गलती।

हालांकि यह थोड़ा उलझन में है। सामान्य स्थिति में, जब एक वस्तु कॉन्स्ट संदर्भ द्वारा किसी अन्य को ले जाती है, तो यह सुझाव देता है कि अस्थायी वस्तु वहां दी जा सकती है। तुम क्या सोचते हो? क्या यह एक बुरा सम्मेलन है? शायद इस तरह के मामलों में ऑब्जेक्ट (संदर्भ के बजाय) का सूचक होना चाहिए? या फिर भी - क्या यह तर्क के लिए कुछ विशेष कीवर्ड उपयोगी नहीं होगा जो अस्थायी वस्तु को पैरामीटर के रूप में अनुमति देने/अस्वीकार करने की अनुमति देता है?

संपादित करें: प्रलेखन (संस्करण 1.49) के बजाय न्यूनतम है और केवल बात यह है कि ऐसी समस्या का सुझाव दे सकते है:

नोट: कोई पार्स वास्तव में निर्माण पर किया जाता है। पार्सिंग मांग पर की जाती है क्योंकि टोकन को शुरुआत से प्रदान किए गए इटरेटर के माध्यम से पहुंचाया जाता है।

लेकिन यह स्पष्ट रूप से यह नहीं बताता है कि दिया गया वही ऑब्जेक्ट का उपयोग किया जाएगा।

हालांकि, इस प्रश्न का बिंदु इस तरह के मामले में कोडिंग शैली के बारे में चर्चा है, यह केवल एक उदाहरण है जिसने मुझे प्रेरित किया।

+0

एक ही चीज़ से काटा गया। जब मैं सक्षम हूं, तो मैं कम से कम संकेत के लिए बूस्ट :: रेफरी का उपयोग करता हूं, कम से कम संकेत देता है कि संदर्भ – Anycorn

+0

संग्रहीत किया जाएगा यदि मुझे बूस्ट :: टोकनज़र में वास्तव में कोई बग है तो मुझे आश्चर्य होगा। – CashCow

+0

@CashCow: यह प्रलेखन में एक बग है, जिसमें 'टोकनज़र' अपने जीवनकाल की अवधि के लिए अपने कन्स्ट्रक्टर तर्क का संदर्भ रखता है जो अस्थायी लोगों के साथ नरक है ... –

उत्तर

8

व्यक्तिगत रूप से मुझे लगता है कि यह एक बुरा विचार है, और यह स्ट्रिंग की प्रतिलिपि बनाने के लिए या const std::string* लेने के लिए कन्स्ट्रक्टर को बेहतर ढंग से लिखना बेहतर होगा। कॉलर के लिए यह केवल एक अतिरिक्त चरित्र है, लेकिन वह चरित्र उन्हें अस्थायी रूप से अस्थायी रूप से उपयोग कर देता है।

नियम के रूप में: लोगों को यह सुनिश्चित करने के बिना लोगों को बनाए रखने के लिए जिम्मेदारियां न बनाएं कि उनके पास यह ज़िम्मेदारी है।

मुझे लगता है कि एक विशेष कीवर्ड भाषा बदलने को उचित ठहराने के लिए एक पूर्ण पर्याप्त समाधान नहीं होगा। यह वास्तव में अस्थायी नहीं है जो समस्या है, यह कोई वस्तु है जो वस्तु के निर्माण से कम समय के लिए रहता है। कुछ परिस्थितियों में एक अस्थायी ठीक होगा (उदाहरण के लिए यदि tokenizer ऑब्जेक्ट स्वयं एक ही पूर्ण अभिव्यक्ति में अस्थायी था)। मैं आधा फिक्स के लिए भाषा के साथ वास्तव में गड़बड़ नहीं करना चाहता हूं, और वहां पूर्ण फिक्स उपलब्ध हैं (उदाहरण के लिए shared_ptr लें, हालांकि इसके अपने मुद्दे हैं)।

"तो मैं इस कल्पना नहीं कर सकते, मेरी गलती"

मुझे नहीं लगता कि यह वास्तव में अपनी गलती, मैं Frerich से सहमत रूप में अच्छी तरह मेरी निजी शैली गाइड के खिलाफ किया जा रहा है के रूप में अगर सब पर यह करने के लिए है कि, आप इसे करते हैं और दस्तावेज़ नहीं करते हैं, तो यह किसी भी उचित शैली मार्गदर्शिका में एक दस्तावेज़ बग है।

यह बिल्कुल जरूरी है कि आवश्यक जीवनकाल के संदर्भ पैरामीटर को दस्तावेज किया गया हो, यदि यह "कम से कम कार्य कॉल" के अलावा कुछ भी है। यह ऐसा कुछ है जो दस्तावेज़ अक्सर के बारे में ढीला होता है, और त्रुटियों से बचने के लिए ठीक से किया जाना चाहिए।

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

दुर्भाग्यवश वास्तव में पर एकमात्र तंत्र सुनिश्चित करता है कि आपका फ़ंक्शन कोई संदर्भ नहीं रख सकता है, वह मूल्य से गुजरना है, जिसमें प्रदर्शन लागत है। यदि आप ऐसी भाषा का आविष्कार कर सकते हैं जो सामान्य रूप से एलियासिंग की अनुमति देता है, लेकिन सी-स्टाइल restrict संपत्ति भी है जो संकलन-समय, कॉन्स-स्टाइल पर लागू होती है, ताकि उनके तर्कों के संदर्भों को दूर करने से कार्यों को दूर किया जा सके, तो शुभकामनाएं और मुझे साइन अप करें ।

+0

मैं आपसे सहमत हूं, और हैरान हूं कि इसे बढ़ावा देने में मदद मिली। मैं गैर-कॉन्स्ट संदर्भ द्वारा पैरामीटर लेता हूं, जो सुनिश्चित करता है कि उपयोगकर्ता अस्थायी रूप से पास नहीं होता है। मैं उन्हें एक std :: स्ट्रिंग सदस्य भी संग्रहीत कर सकता हूं और पास किए गए पैरामीटर के साथ स्वैप कर सकता हूं, और यदि उपयोगकर्ता अपनी मूल स्ट्रिंग चाहते हैं तो उपयोगकर्ता अपनी प्रतिलिपि बना सकते हैं। – CashCow

+0

मेटा टिप्पणी: एक समुदाय विकी उत्तर क्यों है? किसी भी मामले में मुझसे +1। – Francesco

+0

@ फ्रांसेस्को: मैंने एसओ के विषय पर क्या है, यह जानने की कोशिश की है कि यह दूसरों के लिए तय है। लेकिन मैं आमतौर पर राय के सवालों के लिए प्रतिनिधि नहीं लेता हूं। –

11

(इस तरह के एक निर्माता के रूप में) कुछ समारोह के रूप में संदर्भ-टू-स्थिरांक एक तर्क लेता है तो यह या तो

  • दस्तावेज़ स्पष्ट रूप से संदर्भित वस्तु के जीवनकाल कुछ आवश्यकताओं को पूरा करना चाहिए करना चाहिए (में के रूप में "इस से पहले नष्ट नहीं है और ऐसा होता है"

या

)
  • किसी दिए गए ऑब्जेक्ट का उपयोग बाद के बिंदु पर करने की आवश्यकता होने पर आंतरिक रूप से प्रतियां बनाएं।

इस विशेष मामले में (boost::tokenizer वर्ग) मुझे लगता है था कि बाद के प्रदर्शन कारणों से नहीं किया जाता है और/या वर्ग कंटेनर प्रकार जो पहली जगह में भी copyable नहीं हैं के साथ प्रयोग करने योग्य बनाने के लिए । इस कारण से, मैं इसे एक दस्तावेज बग पर विचार करता हूं।

3

जैसा कि अन्य ने कहा, boost::tokenizer उदाहरण tokenizer या किसी दस्तावेज़ से अनुपलब्ध चेतावनी का परिणाम है।

आम तौर पर प्रश्न का उत्तर देने के लिए, मुझे निम्नलिखित प्राथमिकता सूची उपयोगी मिली। यदि आप किसी कारण से कोई विकल्प नहीं चुन सकते हैं, तो आप अगले आइटम पर जाते हैं।

  1. मूल्य द्वारा दर्रा (एक स्वीकार्य कीमत पर copyable और मूल वस्तु को बदलने की जरूरत नहीं है) स्थिरांक संदर्भ द्वारा
  2. दर्रा (संदर्भ द्वारा
  3. दर्रा (मूल वस्तु को बदलने की जरूरत नहीं है) की जरूरत मूल वस्तु) (वस्तु के जीवनकाल कुछ और द्वारा किया जाता है shared_ptr द्वारा
  4. पास बदलने के लिए, यह भी स्पष्ट रूप से इरादा संदर्भ रखने के लिए) कच्चे सूचक द्वारा
  5. दर्रे से पता चलता (आप कास्ट करना एक पते मिला है, या आप किसी कारण से स्मार्ट पॉइंटर का उपयोग नहीं कर सकते हैं)

इसके अलावा, यदि सूची से अगला आइटम चुनने का आपका तर्क "प्रदर्शन" है, तो बैठ जाओ और अंतर को मापें। मेरे अनुभव में, ज्यादातर लोग (विशेष रूप से जावा या सी # पृष्ठभूमि के साथ) किसी वस्तु को मूल्य से गुजरने की लागत का अनुमान लगाते हैं (और डीरफ्रेंसिंग की लागत का अनुमान लगाते हैं)। मूल्य से गुजरना सबसे सुरक्षित विकल्प है (यह ऑब्जेक्ट या फ़ंक्शन के बाहर किसी भी आश्चर्य का कारण नहीं बनता है, न कि किसी अन्य थ्रेड में भी), उस विशाल लाभ को आसानी से न छोड़ें।

1

बहुत समय यह संदर्भ पर निर्भर करेगा, उदाहरण के लिए यदि यह एक मजेदार है जिसे फॉर_एच या इसी तरह कहा जाता है, तो आप अक्सर अपने मज़ेदार के भीतर एक संदर्भ या सूचक को उस ऑब्जेक्ट में संग्रहीत करेंगे जो आपके पास होगा अपने मज़ेदार से परे जीवन भर।

यदि यह सामान्य उपयोग कक्षा है तो आपको यह विचार करना होगा कि लोग इसका उपयोग कैसे करेंगे।

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

const char * संग्रहीत करना std::string const& से बेहतर होगा। यदि उपयोगकर्ता के पास std::string है तो const char * तब तक मान्य रहेगा जब तक कि वे अपनी स्ट्रिंग को संशोधित नहीं करते हैं, और शायद वे नहीं करेंगे। अगर उनके पास एक कॉन्स char * है या कुछ ऐसा है जो वर्णों की सरणी रखता है और इसे पास करता है, तो यह std::string const & बनाने के लिए इसे किसी भी तरह कॉपी करेगा और आप इस तथ्य के बड़े खतरे में हैं कि यह आपके कन्स्ट्रक्टर के पीछे नहीं रहेगा।

बेशक, एक कॉन्स char * के साथ आप अपने कार्यान्वयन में सभी सुंदर std::basic_string फ़ंक्शंस का उपयोग नहीं कर सकते हैं।

पैरामीटर के रूप में लेने के लिए एक विकल्प है, std::string& (कॉन्स्ट संदर्भ नहीं) जिसे गारंटी देना चाहिए (एक अनुपालन कंपाइलर के साथ) कि कोई अस्थायी रूप से पास नहीं होगा, लेकिन आप दस्तावेज़ में सक्षम होंगे कि आप दस्तावेज़ नहीं कर पाएंगे वास्तव में इसे बदलें, और आपके प्रतीत होता है कि आपके कॉन्स-सही कोड के पीछे तर्क नहीं है। ध्यान दें, मैंने अपने कोड में एक बार इस चाल का उपयोग किया है। और आप खुशी से स्ट्रिंग के खोज कार्यों का उपयोग कर सकते हैं। (साथ ही, यदि आप चाहें तो स्ट्रिंग के बजाय मूल_स्ट्रिंग लेना ताकि आप विस्तृत वर्ण तारों को भी टोकननाइज़ कर सकें)।

+0

मैं मानता हूं कि गैर-कॉन्स्ट संदर्भ इस तरह की गलती से बचने में मदद करेगा, लेकिन यह एक तरह का कामकाज है। यह निश्चित रूप से एक साफ समाधान नहीं है, है ना? – peper0

+0

मेरी राय में "कॉन्स्ट char *" ज्यादातर मामलों में समस्या का समाधान नहीं करेगा, क्योंकि मैं अभी भी स्ट्रिंग (कुछ) .c_str() को पार कर सकता हूं जो अस्थायी वस्तु को संदर्भित करता है। – peper0

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