2009-06-24 11 views
14

जब मैं g++संदर्भ-प्रकार रूपांतरण ऑपरेटर: परेशानी के लिए पूछ रहे हैं?

class A {}; 

void foo(A&) {} 

int main() 
{ 
    foo(A()); 
    return 0; 
} 

> g++ test.cpp -o test  
test.cpp: In function ‘int main()’: 
test.cpp:10: error: invalid initialization of non-const reference of type ‘A&’ from a temporary of type ‘A’ 
test.cpp:6: error: in passing argument 1 of ‘void foo(A&)’ 

> g++ test.cpp -o test  
test.cpp: In function ‘int main()’: 
test.cpp:10: error: invalid initialization of non-const reference of type ‘A&’ from a temporary of type ‘A’ 
test.cpp:6: error: in passing argument 1 of ‘void foo(A&)’ 
> g++ test.cpp -o test  
test.cpp: In function ‘int main()’: 
test.cpp:10: error: invalid initialization of non-const reference of type ‘A&’ from a temporary of type ‘A’ 
test.cpp:6: error: in passing argument 1 of ‘void foo(A&)’ 

कुछ प्रतिबिंब के बाद निम्न त्रुटियों को संकलित करता हूं, तो ये त्रुटियां मुझे बहुत समझ में आती हैं। A() केवल एक अस्थायी मान है, न कि स्टैक पर एक असाइन करने योग्य स्थान, इसलिए ऐसा कोई प्रतीत नहीं होता है। यदि उसके पास कोई पता नहीं है, तो मैं इसका संदर्भ नहीं रख सकता। अच्छा ठीक है।

लेकिन प्रतीक्षा करें! यदि मैं निम्न xxx47

class A 
{ 
public: 
    operator A&() { return *this; } 
}; 

में निम्न रूपांतरण ऑपरेटर जोड़ता हूं तो सब ठीक है! मेरा सवाल यह है कि क्या यह भी दूरस्थ रूप से सुरक्षित है। Xzx48 क्या इंगित करता है जब A() एक अस्थायी मान के रूप में बनाया गया है?

मुझे इस तथ्य से कुछ विश्वास दिलाया गया है कि

void foo(const A&) {} 

g++ और अन्य सभी कंपाइलर्स के अनुसार अस्थायी मूल्यों को स्वीकार कर सकता है। Xzx51 कीवर्ड हमेशा काटा जा सकता है, इसलिए यह मुझे आश्चर्यचकित करेगा यदि const A& पैरामीटर और A& पैरामीटर के बीच कोई वास्तविक अर्थपूर्ण अंतर था। तो मुझे लगता है कि यह मेरा प्रश्न पूछने का एक और तरीका है: const एक अस्थायी मूल्य का संदर्भ क्यों है जिसे संकलक द्वारा सुरक्षित माना जाता है जबकि एक गैर- const संदर्भ नहीं है?

उत्तर

16

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

void plus_one(int & x) { ++x; } 

int main() { 
    int x = 2; 
    float f = 10.0; 

    plus_one(x); plus_one(f); 

    cout << x << endl << f << endl; 
} 

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


नियम कभी-कभी गड़बड़ होता है। एक आम उदाहरण (वर्णित here), फ़ाइल खोलने, कुछ प्रिंट करने और इसे बंद करने का प्रयास कर रहा है।आप ऐसा करने में सक्षम होना चाहता हूँ चाहते हैं:

ofstream("bar.t") << "flah"; 

लेकिन तुम नहीं क्योंकि ऑपरेटर < < एक रेफरी करने वाली गैर स्थिरांक लेता कर सकते हैं। अपने विकल्पों से दो पंक्तियों में टूट रहे हैं, या एक विधि एक रेफरी करने वाली गैर स्थिरांक लौटने फोन:

ofstream("bar.t").flush() << "flah"; 
+0

मैं मानता हूं कि इस तरह की चीज आमतौर पर प्रोग्रामर त्रुटि होती है। यदि आप उत्सुक हैं, तो कक्षा जिसे मैं संदर्भ के रूप में पास करने की कोशिश कर रहा हूं वह एक प्रकार का स्मार्ट सूचक है, जिसमें अंतर्निहित ढेर-आवंटित सूचक सदस्य हैं। मैं वास्तव में प्राप्त करने वाले फ़ंक्शन को अंतर्निहित सूचक के साथ काम करना चाहता हूं। मैं सिर्फ यह सुनिश्चित करना चाहता हूं कि प्राप्त करने वाले फ़ंक्शन रिटर्न के बाद अस्थायी स्मार्ट पॉइंटर नष्ट नहीं होता है (संदर्भ गणना में कमी)। – Ben

+1

यदि आपका इरादा है, तो या तो स्टैक पर स्मार्ट पॉइंटर स्पष्ट रूप से घोषित करें और इसे पास करें या इसे मूल्य में पास करें। यदि आप इसे मूल्य में पास करते हैं तो आपको गारंटी दी जाती है कि जब तक कार्य समाप्त नहीं हो जाता तब तक इसे नष्ट नहीं किया जाएगा। – MSN

+0

@बेन - इसके बारे में मेरे पोस्ट में कुछ जोड़ा। यह नहीं कह सकता कि क्या यह आपके कोड को देखे बिना आपके लिए एक अच्छा विचार है, लेकिन कुछ उपयोग के मामले हैं (और यह तब तक नष्ट नहीं होगा जब तक यह वापस नहीं आ जाता) –

4

जब आप किसी कॉन्स्ट संदर्भ के लिए आर-मान असाइन करते हैं, तो आपको गारंटी दी जाती है कि संदर्भ नष्ट होने तक अस्थायी नहीं नष्ट हो जाएगा। जब आप एक गैर-कॉन्स्ट संदर्भ को आवंटित करते हैं, तो ऐसी कोई गारंटी नहीं दी जाती है।

int main() 
{ 
    const A& a2= A(); // this is fine, and the temporary will last until the end of the current scope. 
    A& a1 = A(); // You can't do this. 
} 

आप सुरक्षित रूप से कॉन्स्टेस को दूर नहीं कर सकते हैं और चीजों को काम करने की उम्मीद कर सकते हैं। कॉन्स और गैर-कॉन्स संदर्भों पर विभिन्न अर्थशास्त्र हैं।

+0

सामान्य रूप से, इसे बनाए गए अभिव्यक्ति का मूल्यांकन करने के अंत में एक अस्थायी नष्ट हो जाता है। अस्थायी विस्तार के समय दो अपवाद होते हैं, उनमें से एक @Eclipse द्वारा इंगित किया जाता है। देखें: http://en.cppreference.com/w/cpp/language/lifetime#Temporary_object_lifetime – winnetou

3

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

यह प्रतिमान विजुअल स्टूडियो 2005 और 2008 में काम करता था, और हमें इसे पुन: सक्रिय करना पड़ा ताकि सूची को जी ++ के साथ संकलित करने के लिए स्वामित्व-द्वारा-कॉलर-एंड-म्यूटेटेड के बजाय बनाया गया और वापस कर दिया गया हो।

यदि एमएसवीसी में इस तरह के व्यवहार को अस्वीकार करने या इसे g ++ में अनुमति देने के लिए कंपाइलर स्विच सेट करने का कोई तरीका है, तो मुझे यह जानकर उत्साहित होगा; एमएसवीसी कंपाइलर की अनुमति या जी ++ कंपाइलर की प्रतिबंधितता कोडिंग पोर्टिंग में जटिलताओं को जोड़ती है।