2012-05-26 15 views
22

कई स्थानों में मैं कॉपी और चाल निर्माताओं की सिफारिश हस्ताक्षर के रूप में दिया देखा है:क्या एक चालक कन्स्ट्रक्टर एक कॉन्स या गैर-कॉन्स रावल्यू संदर्भ लेना चाहिए?

struct T 
{ 
    T(); 
    T(const T& other); 
    T(T&& other); 
}; 

कहाँ प्रतिलिपि निर्माता एक स्थिरांक संदर्भ लेता है, और इस कदम निर्माता एक गैर स्थिरांक rvalue संदर्भ लेता है।

जहां तक ​​मेरा हालांकि देख सकते हैं, यह मेरे इस कदम अर्थ विज्ञान का लाभ लेने जब इस तरह के नीचे मामले में एक समारोह से स्थिरांक वस्तुओं, लौटने से बचाता है:

T generate_t() 
{ 
    const T t; 
    return t; 
} 

परीक्षण इस VC11 बीटा के साथ, T ' एस कॉपी कन्स्ट्रक्टर कहा जाता है, और चालक कन्स्ट्रक्टर नहीं। यहां तक ​​कि return std::move(t); का उपयोग कर कॉपी कन्स्ट्रक्टर अभी भी कहा जाता है।

मैं देख सकता हूं कि यह कैसे समझ में आता है, क्योंकि t है इसलिए T&& से बंधना नहीं चाहिए। कन्स्ट्रक्टर हस्ताक्षर में const T&& का उपयोग करना ठीक काम करता है, और समझ में आता है, लेकिन फिर आपको समस्या है क्योंकि other कॉन्स है, यदि आप बाहर निकलने की आवश्यकता है तो आप अपने सदस्यों को बाहर नहीं कर सकते हैं - यह केवल तभी काम करेगा जब सभी सदस्य स्केलर हैं या सही हस्ताक्षर के साथ रचनाकारों को स्थानांतरित कर चुके हैं।

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

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

+2

ठीक है, मुझे लगता है कि लौटने वाले स्थिर अस्थायी के उपयोग के मामले कुछ हद तक छोटे हैं। यदि आप इसे पहले से घोषित करते हैं, तो आप लौटने से पहले कुछ चीजें करना चाहते हैं। यदि नहीं, तो एक सरल 'वापसी टी() 'वैसे भी करेगा। हालांकि मैं अभी भी कुछ उपयोग मामलों को देख सकता हूं, मुझे लगता है कि वे दुर्लभ हैं। और निश्चित रूप से, एक रावल्यू संदर्भ जिसमें से आप संसाधनों को चुरा नहीं सकते हैं, वास्तव में किसी लाल्व संदर्भ की तुलना में किसी भी मूल्य का नहीं है। इंटरस्टेस्टिंग सवाल, यद्यपि। –

+1

वैसे, क्या यह कोड एनआरवीओ के लिए योग्य नहीं है? तो "क्या होना चाहिए" यह है कि 'कॉन्स्ट' ऑब्जेक्ट 'टी' गैर-कॉन्स रिटर्न मान के समान स्थान पर बनाया गया है। फिर यदि आवश्यक हो तो गैर-कॉन्स रिटर्न वैल्यू * को कॉलर द्वारा गैर-कॉन्स मूव कन्स्ट्रक्टर (या एक मूव असाइनमेंट ऑपरेटर) के माध्यम से स्थानांतरित किया जा सकता है। निर्माण के मामले में, फिर भी यह प्रतिलिपि elision के लिए योग्य होगा और 'gener_t()' पर कॉल का उपयोग करके जो कुछ भी शुरू किया जा रहा है उसे सीधे बनाया जा सकता है। इस अनुकूलन को बनाने से वीसी 11 में क्या बाधा आ रही है? –

+1

_consting चीजें अच्छी फॉर्म_ नहीं है अगर आप उन्हें संशोधित करना चाहते हैं, उदा। उनसे आगे बढ़कर। –

उत्तर

18

यह गैर-const रैवल्यू संदर्भ होना चाहिए।

यदि कोई ऑब्जेक्ट केवल-पढ़ने वाली मेमोरी में रखा गया है, तो आप इसके संसाधनों को चुरा नहीं सकते हैं, भले ही इसका औपचारिक जीवनकाल समाप्त हो रहा हो। C++ में const के रूप में बनाए गए ऑब्जेक्ट्स को केवल-पढ़ने वाली मेमोरी में रहने की अनुमति है (const_cast का उपयोग करके उन्हें अपरिभाषित व्यवहार में बदलने की कोशिश करने के लिए)।

+2

संभावना है कि यह मामला नहीं है। एक वस्तु जिसे आप स्थानांतरित कर सकते हैं, यह इंगित करता है कि यह संसाधनों का प्रबंधन करता है, इसलिए ऑब्जेक्ट का निर्माण होने पर स्मृति को लिखने योग्य होना चाहिए, और संभवतः यह एक विनाशक है जो उन संसाधनों को जारी करता है, इसलिए फिर, इसे विनाश के दौरान लिखना होगा। मुझे संदेह है कि संकलक स्मृति पृष्ठ को निर्माण के बाद केवल पढ़ने के लिए कोड उत्पन्न करेगा और फिर इसे विनाश से पहले लिखने योग्य चिह्नित करेगा (और विनाश के बाद केवल पढ़ने के बाद ही संभवतः ऑब्जेक्ट उस स्मृति पृष्ठ में अकेला नहीं है .. ।) कहा जा रहा है कि +1 –

+0

@ डेविड: "मुझे शक है कि ..." - सच है, लेकिन यह डीबग मोड, esp में उपयोगी सुविधा हो सकती है। विरासत कॉन्स-गलत कोड को ठीक करते समय। मुझे लगता है कि महत्वपूर्ण बात यह है कि यद्यपि यह बात वास्तव में नहीं होगी, तथ्य यह है कि यह कानूनी है कि आप अपने विनाशक से पहले कॉन्स्ट ऑब्जेक्ट्स को संशोधित क्यों नहीं कर सकते हैं (और विशेष रूप से उनसे कुशलतापूर्वक उनसे स्थानांतरित नहीं हो सकते हैं जहां वे संसाधन रखते हैं) । –

+0

@SteveJessop: +1 के लिए यही कारण है: क्या ऑब्जेक्ट केवल पढ़ने योग्य स्मृति में है या नहीं, इस तथ्य को नहीं बदलेगा कि निरंतर वस्तु से बाहर निकलने से अनुबंध टूट रहा है: आप ऐसा कुछ संशोधित कर रहे हैं जिसे आपने वादा नहीं किया था स्पर्श करें। –

8

एक चालक कन्स्ट्रक्टर सामान्य रूप से एक गैर-कॉन्स्ट संदर्भ लेना चाहिए।

यदि किसी कॉन्स ऑब्जेक्ट से स्थानांतरित करना संभव था तो आमतौर पर यह इंगित करता था कि यह किसी ऑब्जेक्ट की प्रतिलिपि बनाने के लिए उतना ही कुशल था जितना कि इसे "स्थानांतरित करना" था। इस बिंदु पर एक चालक कन्स्ट्रक्टर होने के लिए आमतौर पर कोई लाभ नहीं होता है।

आप यह भी सही हैं कि यदि आपके पास एक वैरिएबल है जिसे आप संभावित रूप से स्थानांतरित करना चाहते हैं तो इसे गैर-कॉन्स होना चाहिए।

जैसा कि मैं समझता हूं, यही कारण है कि स्कॉट मेयर्स ने सी ++ 11 के कार्यों से मूल्य के आधार पर वर्ग प्रकार की वस्तुओं को वापस करने पर अपनी सलाह बदल दी है। कॉन्स्टेबल वैल्यू द्वारा रिटर्निंग ऑब्जेक्ट्स अस्थायी रूप से अस्थायी ऑब्जेक्ट को संशोधित करता है लेकिन यह रिटर्न वैल्यू से आगे बढ़ता है।

5

क्या एक चालक कन्स्ट्रक्टर एक कॉन्स या गैर-कॉन्स्ट रावल्यू संदर्भ लेना चाहिए?

इसे गैर-कॉन्स्ट रावल्यू संदर्भ लेना चाहिए।रैवल्यू संदर्भ सबसे पहले उनके कॉन्स फॉर्म में समझ में नहीं आता है क्योंकि आप उन्हें संशोधित करना चाहते हैं (एक तरह से, आप "स्थानांतरित करें", आप अपने आंतरिक के लिए अपने आंतरिक चाहते हैं)।

इसके अलावा, वे स्थिरांक बिना उपयोग के लिए डिज़ाइन किया गया है और मेरा मानना ​​है कि एक स्थिरांक rvalue संदर्भ के लिए केवल उपयोग बहुत बहुत रहस्यमय कुछ है कि स्कॉट Meyers this बात में उल्लेख किया है।

क्या मैं तर्क के इस पंक्ति में सही हूं? मुझे उन चीज़ों को वापस करना बंद करना चाहिए जो स्थिर हैं?

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

यह लौटने भी lvalue संदर्भ में "घायल" होने का rvalue संदर्भ का कारण होता है और आप आमतौर पर नहीं करना चाहते हैं कि, इसलिए, ऊपर उल्लिखित कार्यक्षमता के साथ सही अग्रेषण मुद्दे को हल करती है।

कहा जा रहा है कि, मैं सुझाव देता हूं कि आप बस उस लिंक पर नज़र डालें जिस पर मैंने एक लिंक पोस्ट किया था।

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