2010-02-06 24 views
15

मैं कॉपी कन्स्ट्रक्टर के यांत्रिकी के रूप में थोड़ा उलझन में हूँ। अगर मैं गलत हूं तो मुझे सही करें:क्या मैं एक कॉपी कन्स्ट्रक्टर को स्पष्ट रूप से कॉल कर सकता हूं?

यदि कोई विधि पैरामीटर के रूप में किसी ऑब्जेक्ट का संदर्भ लेती है, और कक्षा एक प्रतिलिपि को परिभाषित करती है, तो कक्षा स्वयं की एक प्रति बनाने के लिए निर्माता का उपयोग करती है और जो इसे पास हो जाती है मूल वस्तु के संदर्भ के बजाय समारोह?

इसके अलावा, एक anotherObject की एक प्रतिलिपि बनाने के लिए

Object * obj = new Object(&anotherObject); 

कॉल कर सकते हैं?

+1

आपका शब्दावली का सुझाव नहीं होना चाहिए कि 'anotherObject' स्वयं की प्रतिलिपि पैदा कर रही है .. उद्देश्य यह है कि नए के बाद बनाई गई है' की एक प्रति बनाने वाले हैं anotherObject'। –

+5

@ हसन: ओपी पूछे बिना प्रश्न का अर्थ न बदलें। यह एक महत्वपूर्ण भेद है। '& anotherObject' एक सूचक है, संदर्भ नहीं। –

+0

"कोई यह नहीं बता सकता" कि 'नया ऑब्जेक्ट (और अन्य ऑब्जेक्ट)' किसी अन्य ऑब्जेक्ट की प्रतिलिपि बना देगा (जो शब्द सुझाव दे रहा है)। उस कथन को सही रखने के लिए, वाक्यविन्यास को समायोजित करने की आवश्यकता है। –

उत्तर

26

नहीं है, एक समारोह के लिए एक संदर्भ लेते हैं:

void f1(Object & o); // call by reference 

तो कोई नकल किया जाता है। यदि कोई फ़ंक्शन कोई मान लेता है:

void f2(Object o); // call by value 

तो प्रतिलिपि प्रतिलिपि का उपयोग कर संकलक द्वारा प्रतिलिपि बनाई गई है।

और हाँ, जब आप कहते हैं:

Object * obj = new Object(anotherObject); // not &anotherObject 

प्रतिलिपि निर्माता स्पष्ट रूप से प्रयोग किया जाता है (यह मानते हुए anotherObject प्रकार वस्तु की है।) new यहाँ के उपयोग के बारे जादू कुछ भी नहीं है, तथापि नहीं है - इस मामले में:

Object obj2(anotherObject); 

कॉपी कन्स्ट्रक्टर का भी उपयोग किया जाता है।

+1

"तो प्रतिलिपि प्रतिलिपि का उपयोग कर संकलक द्वारा प्रतिलिपि बनाई गई है।" - यह चालक-कन्स्ट्रक्टर का उपयोग कर सकता है, और यह एक कॉपी-एलिजन परिदृश्य भी है, इसलिए शायद कोई भी कन्स्ट्रक्टर भी नहीं। –

7

यदि कोई विधि पैरामीटर पैरामीटर के रूप में किसी ऑब्जेक्ट का संदर्भ लेती है, तो प्रतिलिपि बनाने वाले निर्माता को नहीं कहा जाएगा। अगर ऐसा होता है, तो कॉपी कन्स्ट्रक्टर के लिए एक कॉल के परिणामस्वरूप अनंत लूप होता है (क्योंकि यह तर्क के रूप में संदर्भ लेता है)।

वह लाइन एक प्रतिलिपि निर्माता को कॉल करने का एक वैध तरीका नहीं है। यह एक संदर्भ के रूप में एक संदर्भ के रूप में एक संदर्भ की उम्मीद है।

+0

असल में, कॉपी-कन्स्ट्रक्टर तर्क ठोस नहीं है। भाषा मानक कुछ मामलों में वैकल्पिक प्रतिलिपि की अनुमति देता है और स्पष्ट रूप से नोट करता है कि कार्यान्वयन को यह सुनिश्चित करना है कि कॉपी-कन्स्ट्रक्टर के मामले में कोई अनंत रिकर्सन नहीं है, एक उदाहरण के रूप में (सी ++ 03 में फुटनोट 93 देखें) – AnT

+0

@AndreyT: दिलचस्प। वैसे भी, यह इस मामले में चीजों को नहीं बदलेगा क्योंकि हम संदर्भ के मामले में * नहीं * प्रतिलिपि के बारे में बात कर रहे हैं, जो एक निश्चित निश्चित बात है। –

+0

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

1

दोनों मामलों में नहीं। पहले मामले में, उस ऑब्जेक्ट का संदर्भ स्वयं पारित हो गया है और कॉपी नहीं बनाई गई है। दूसरे मामले में आप object के निर्माता को पॉइंटर पास कर रहे हैं इसलिए कोई प्रतिलिपि बनाई गई नहीं है। तो वस्तु एक निर्माता (नहीं एक प्रतिलिपि निर्माता), जो की तरह object(anotherClass*)

1

कॉपी निर्माता कुछ ही कहा जाता है जब, नहीं संदर्भ द्वारा मूल्य द्वारा गुजर है होना चाहिए। संदर्भ के अनुसार कोई प्रतिलिपि की आवश्यकता नहीं है (यह किस संदर्भ के लिए है इसका हिस्सा है!) इसलिए कोई कॉपी कन्स्ट्रक्टर नहीं कहा जाता है।

3

तथ्य यह है कि आप एक विधि कॉल कर रहे हैं, यहां कोई महत्व नहीं है। फंक्शन कॉल के दौरान संदर्भ पैरामीटर प्रारंभिक स्टैंडअलोन संदर्भ प्रारंभ से अलग नहीं है और उसी नियम द्वारा शासित है।

संदर्भ प्रारंभिकरण के नियम थोड़ा जटिल हैं, लेकिन नीचे की रेखा यह है कि यदि प्रारंभकर्ता एक लवल्यू (आपके मामले में विधि कॉल में तर्क) है और संदर्भ का प्रकार समान प्रकार के जैसा है प्रारंभकर्ता (यानी पैरामीटर का प्रकार तर्क प्रकार के समान होता है), तो संदर्भ सीधे बाध्य होगा। अर्थात। कोई प्रतिलिपि नहीं बनाई गई है।

Object a; // class type 
Object &r = a; // no copying 
const Object &cr = a; // no copying 

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

const Object &tr = Object(); 

copyings के कार्यान्वयन पर निर्भर परिमित संख्या के साथ

const Object &tr = Object(Object(Object(Object()))); 

के रूप में संकलक द्वारा व्याख्या की जा सकती। निस्संदेह, दक्षता कारणों के लिए संकलक सामान्य रूप से अनावश्यक प्रतियां बनाने की कोशिश नहीं कर रहे हैं, भले ही उन्हें कॉपी करने की अनुमति दी जाए।

एक उत्कृष्ट उदाहरण है कि अक्सर संकलक की नकल व्यवहार की वैधता के बारे में बहस stirs एक निम्नलिखित

Object a; 
const Object &r = <some condition> ? a : Object(); 

की तरह भाव में संदर्भ आरंभीकरण एक व्यक्ति सी ++ संदर्भ अर्थ विज्ञान से परिचित समझना होगा कि है की तरह भाव उपरोक्त संदर्भ प्रारंभिकरण के दौरान अनावश्यक प्रतिलिपि करने के लिए मानक अनुमति के पीछे तर्क की संभावना है।

+0

क्या आप निश्चित अनंत गलती के बारे में निश्चित हैं? सी ++ 03 8.5.3 कहता है कि केवल दो मामले हैं: (ए) "संदर्भ उस वस्तु के भीतर रावल्यू (3.10 देखें) या उप-ऑब्जेक्ट द्वारा प्रतिनिधित्व की गई वस्तु के लिए बाध्य है", और (बी) " एक अस्थायी प्रकार "सीवी 1 टी 2" [एसआईसी] बनाया गया है, और एक कन्स्ट्रक्टर को पूरे रावल्यू ऑब्जेक्ट को अस्थायी रूप में कॉपी करने के लिए बुलाया जाता है। संदर्भ अस्थायी या अस्थायी के भीतर उप-ऑब्जेक्ट के लिए बाध्य है। ध्यान दें कि मामला (बी) कहता है * * से बाध्य *, * * से शुरू नहीं हुआ, इसलिए मुझे नहीं पता कि यह (बी) एक अतिरिक्त अस्थायी से कहीं अधिक अनुमति देता है। –

+0

बेशक, सी ++ 14 (जो आपके उत्तर के बाद आया था) केवल केस (ए) की अनुमति देता है, यानी 'ऑब्जेक्ट() 'के अलावा कोई और अस्थायी नहीं बनाया जा सकता है। मैंने सी ++ 11 के शब्द की जांच नहीं की, हालांकि ISTR को रावल से संदर्भ प्रारंभिकरण के संबंध में एक दोष था। –

0

हाँ नियुक्ति नए का उपयोग कर तो जैसे:

Object dstObject; 
new(&dstObject) Object(&anotherObject); 
संबंधित मुद्दे

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