2016-02-27 11 views
12

इस ऑब्जेक्ट पर रिटर्निंग संदर्भ अक्सर assignment operator overloading में उपयोग किया जाता है। इसे named parameters idiom के आधार के रूप में भी उपयोग किया जाता है जो कॉलर विधियों को कॉल की श्रृंखला द्वारा ऑब्जेक्ट प्रारंभ करने की अनुमति देता है: Params().SetX(1).SetY(1) जिनमें से प्रत्येक * के संदर्भ में आता है।क्या यह संदर्भ के रूप में * इसे वापस सुरक्षित करना सुरक्षित है?

लेकिन *this के संदर्भ में वापस लौटना सही है। क्या होगा यदि हम अस्थायी वस्तु के लिए इस संदर्भ को संदर्भित करने के लिए विधि को कॉल करते हैं:

#include <iostream> 

class Obj 
{ 
public: 
    Obj(int n): member(n) {} 
    Obj& Me() { return *this; } 

    int member; 
}; 

Obj MakeObj(int n) 
{ 
    return Obj(n); 
} 

int main() 
{ 
    // Are the following constructions are correct: 
    std::cout << MakeObj(1).Me().member << std::endl; 
    std::cout << Obj(2).Me().member << std::endl; 
    Obj(3).Me() = Obj(4); 

    return 0; 
} 
+5

उन दोनों उपयोग सुरक्षित हैं। समस्या तब उत्पन्न होगी जब कॉलिंग कोड वर्तमान कथन से अधिक लंबे समय तक संदर्भ रखने की कोशिश करता है, उदा। 'ऑटो और रेफरी = MakeObj (5) .Me();'। हां, आप एक ऐसे आभासी वस्तु को बना सकते हैं जो इस तरह एक अस्थायी वस्तु को निर्दिष्ट करता है (जो एक कारण है कि मैं अक्सर उन लोगों को सही करता हूं जो "अस्थायी वस्तु" और "रावल्यू" शब्दों का उपयोग करते हैं। –

+0

मैंने देखा कि मानक पुस्तकालय भी इस * http - : //www.cplusplus.com/reference/vector/vector/operator=/: "वापसी मान: * यह"। मानक पुस्तकालय गलत निर्माण का उपयोग करता है तो यह अजीब होगा। :) –

उत्तर

7

हाँ, यह * इस वापस जाने के लिए सुरक्षित है।

अस्थायी वस्तुओं पूर्ण अभिव्यक्ति (1.9) का मूल्यांकन करने में अंतिम चरण के रूप में नष्ट कर रहे हैं कि (lexically) शामिल हैं: आसान मामला है जब यह एक अस्थायी नहीं है, हालांकि तब भी जब यह है, यह संभव हो जाना चाहिए है वह बिंदु जहां वे बनाए गए थे। यह सच है भले ही वह मूल्यांकन अपवाद फेंकने में समाप्त होता है (सी ++ 03 §12.2/3)।

दूसरे शब्दों में, जब तक आप सेमी-कोलन तक नहीं पहुंच जाते, सब कुछ ठीक (सिद्धांत में) होना चाहिए।

तो निम्नलिखित कोड काम करना चाहिए:

std::cout << MakeObj(1).Me().member << std::endl; 

हालांकि यह काम नहीं करना चाहिए:

const Obj &MakeMeObj(int n) { return Obj(n).Me(); } 
std::cout << MakeMeObj(1).member << std::endl; 

यह तार्किक है, जैसा कि आप एक अस्थायी के लिए एक संदर्भ लौट रहे हैं। अधिकांश कंपाइलर इस पर चेतावनी देते हैं/त्रुटि करते हैं, हालांकि यदि आप जटिल हो जाते हैं, तो यह देखने के लिए कुछ है।

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

Obj &Me() & { return *this; } 
Obj &Me() && = delete; 
+0

इस तरह के अधिभार को इंगित करने के लिए धन्यवाद। इसका नाम कैसा है? सी ++ मानक के किस संस्करण ने इसे पेश किया? –

+2

मुझे लगता है कि यह सी ++ 11 है, हालांकि कम से कम MSVC2013 का समर्थन नहीं है। जो मैं पढ़ सकता हूं उससे http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm मैं इसे इस-पीआरटी के रेफ-क्वालीफायर पर फ़ंक्शन ओवरलोडिंग कहूंगा, आधिकारिक नाम नहीं पता। – JVApen

3

हाँ, यह सुरक्षित है। अस्थायी वस्तु का जीवन बयान के अंत तक होगा (अधिक पूर्ण रूप से पूर्ण अभिव्यक्ति का मूल्यांकन जिसमें इसे बनाया गया है)। इस मानक द्वारा गारंटीकृत है:

12,2/3: अस्थायी वस्तुओं पूर्ण अभिव्यक्ति है कि (lexically) बिंदु है जहां वे शामिल होते हैं का मूल्यांकन करने में अंतिम चरण के रूप में नष्ट कर रहे हैं।

किसी संदर्भ के लिए बाध्य होने पर अस्थायी जीवनकाल कुछ शर्तों के तहत भी बढ़ाया जा सकता है। लेकिन यहाँ चमत्कार की उम्मीद मत करो। कथन से परे संदर्भ रखने की कोशिश कर रहा है (पता ले कर या संदर्भ निर्दिष्ट करके f.ex) जल्दी से यूबी (demo) का नेतृत्व कर सकता है।

यदि आप const ऑब्जेक्ट्स पर इस तरह के निर्माण का उपयोग करेंगे तो आपको कुछ परेशानी भी होगी क्योंकि आप एक गैर const रेफरी वापस करने का प्रयास करेंगे (लेकिन यह असाइनमेंट और सेटर्स के लिए आपके उदाहरणों में प्रासंगिक नहीं है)।

+1

'कॉन्स्ट ओबज एंड मी() कॉन्स {रिटर्न * यह जोड़ना; } 'एक ओवरलोड के रूप में कॉन्स ऑब्जेक्ट्स के लिए समर्थन जोड़ता है। – StellarVortex

+0

@StellarVortex हाँ, exacly! मैं सिर्फ ध्यान आकर्षित करना चाहता था कि सामान्य स्थिरता या संचालन की गैर-स्थिरता में सावधानी से विचार किया जाना चाहिए विशेष रूप से संदर्भ के लिए '* यह' लौटने पर। निश्चित रूप से असाइनमेंट ऑपरेटर और सेटर्स के लिए यह कोई मुद्दा नहीं होगा ;-) – Christophe

4
// Are the following constructions are correct: 
std::cout << MakeObj(1).Me().member << std::endl; 
std::cout << Obj(2).Me().member << std::endl; 

हाँ, क्योंकि प्रत्येक सभी अस्थायी वस्तुओं के जीवन रेखा में खाते में पूर्ण अभिव्यक्ति लेने के लिए बढ़ा दिया गया है।

cppreference.com के रूप में कहते हैं:

(...) सभी अस्थायी वस्तुओं में अंतिम चरण पूर्ण अभिव्यक्ति है कि (lexically) बिंदु जहां वे बनाए गए थे (शामिल के मूल्यांकन के रूप में नष्ट कर रहे हैं .. ।)।

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

// not allowed: 
Obj& ref = MakeObj(1); 
std::cout << ref.Me().member << std::endl; 

अन्य मामलों में, संकलक बहुत चालाक को देखने के लिए नहीं हो सकता है समस्या यह है, किसी भी नैदानिक ​​संदेश दे रही है, और अंत में अपने कार्यक्रम में अपरिभाषित व्यवहार के निर्माण के बिना अपने निष्पादन योग्य बनाने के लिए:

// undefined behaviour: 
Obj &ref = MakeObj(1).Me(); 
std::cout << ref.member << std::endl; 
+0

@ एमएम: धन्यवाद, मैंने उदाहरण जोड़ा। –

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