2012-11-14 17 views
23

यहां कोड है जो g ++ 4.7 और vs2012 (cl17) में अलग-अलग आउटपुट उत्पन्न करता है।सी ++: फ़ंक्शन पैराम के मान द्वारा प्रतिलिपि बनाम बनाम बनाम2012

#include <iostream> 

using namespace std; 

class A 
{ 
public: 
    A() { cout << "1" << endl; } 
    ~A() { cout << "2" << endl; } 
}; 

class B : public A 
{ 
public: 
    B() { cout << "3" << endl; } 
    ~B() { cout << "4" << endl; } 
}; 

void func(A a) {} 

int main() 
{ 
    B b; 
    func(b); 
    return 0; 
} 

जीसीसी उत्पादन 13242 है, जबकि सीएल आउटपुट 132242

सीएल कंपाइलर दूसरे A ऑब्जेक्ट का उत्पादन क्यों करता है जबकि यह स्टैक पर एक प्रति बनाता है, और किस उद्देश्य के लिए?

+2

VS2010 पर यह परीक्षण किया है, परिणाम है "132,242" – Apokal

+1

बजना 4.1 पैदा करता है "13242" –

+4

वी.एस. रिलीज़ संस्करण केवल 13242 उत्पादन नहीं बल्कि डिबग संस्करण – billz

उत्तर

-3

आपको एक कंपाइलर की बग का सामना करना पड़ा।


समारोह func वस्तु की एक प्रतिलिपि बनाने (लेकिन टुकड़ा करने की क्रिया के लिए बाहर घड़ी) की जरूरत है:

को उचित रूप से नीचे समझाया गया है।

तो, क्या होता है यह है:

int main() 
{ 
    // create object B, which first creates the base object A 
    B b; 
    // create object A, using this copy constructor : A(const B&) 
    func(b); 
} 

जब कॉपी-निर्माण वस्तु एक func कॉल के अंत में नष्ट हो जाता है अतिरिक्त ~ एक() कॉल किया जाता है।

+5

"सीएल आउटपुट" में 'func()' के अंत में '~ A' पर दो कॉल हैं। ऐसा लगता है कि सवाल है। –

+0

@ केविनबालार्ड मैंने समझाया कि क्या होना चाहिए। मैं व्यवहार को एक कंपाइलर की बग कहूंगा। कुछ इसे एक विस्तार कहते हैं;) –

+2

@ BЈовић पहले से ही सवाल में क्या होना चाहिए; यह सिर्फ एक विश्राम है। – Gorpik

5

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

ध्यान दें कि यदि बेहतर रूपांतरण उपलब्ध था, तो इसका उपयोग किया जाएगा। उदाहरण के लिए: यदि A में एक निर्माता A::A(B const&) था, तो कॉपी कन्स्ट्रक्टर के अतिरिक्त, तो इस कन्स्ट्रक्टर का उपयोग कॉपी कन्स्ट्रक्टर के बजाय किया जाएगा।

+4

'ए' के ​​लिए एक स्पष्ट मामूली प्रतिलिपि निर्माता VS2010 में समस्या को हल करता है, जो मुझे अधिक समझ में नहीं आता है। – Gorpik

+1

@ गोर्पिक: यह मानने का अधिक कारण है कि यह इस कोने के मामले के लिए एक कंपाइलर बग है। ओवरलोड रिज़ॉल्यूशन नियम जटिल हैं लेकिन यह मामला अधिक आम लोगों में से एक प्रतीत होता है। –

+1

क्या कोई संकलक बग के साथ समझ सकता है? संकलक को थोड़ा अलग प्रतीकात्मक प्रतिनिधित्व उत्पन्न करने के लिए मजबूर करना आसानी से बग को छुपा सकता है। – Suma

0

सी ++ कंपाइलर निम्न स्थिति में डिफ़ॉल्ट प्रतिलिपि निर्माता को संश्लेषित करेगा। (अंदर सी ++ ऑब्जेक्ट मॉडल से)

  1. वर्ग एक वर्ग है जिसके लिए एक प्रतिलिपि निर्माता मौजूद है के एक सदस्य वस्तु शामिल है।
  2. जब कक्षा को बेस क्लास से लिया जाता है जिसके लिए प्रतिलिपि निर्माता मौजूद होता है।
  3. जब वर्ग एक या अधिक आभासी कार्यों की घोषणा करता है
  4. जब कक्षा विरासत श्रृंखला से ली जाती है जिसमें एक या अधिक आधार वर्ग आभासी होते हैं।

हम कक्षा ए को 4 स्थितियों में नहीं देख सकते हैं। तो सीएल इसके लिए डिफ़ॉल्ट प्रतिलिपि कन्स्ट्रक्टर संश्लेषित नहीं करते हैं। शायद यही कारण है कि 2 temp एक वस्तुओं का निर्माण और नष्ट कर दिया।

निराशाजनक खिड़की से, हम निम्नलिखित कोड देख सकते हैं, कोई ए :: ए कहा जाता है।:

B b; 
00B317F8 lea   ecx,[b] 
00B317FB call  B::B (0B31650h) 
00B31800 mov   dword ptr [ebp-4],0 
func(b); 
00B31807 mov   al,byte ptr [ebp-12h] 
00B3180A mov   byte ptr [ebp-13h],al 
00B3180D mov   byte ptr [ebp-4],1 
00B31811 movzx  ecx,byte ptr [ebp-13h] 
00B31815 push  ecx 
00B31816 call  func (0B31730h) 

लेकिन अगर हम विनाशक वर्चुअल बनाते हैं। हमें निम्नलिखित डिस्सेबल कोड मिलेंगे, हम ए :: ए को बुला सकते हैं। फिर परिणाम अपेक्षित है, केवल 1 ऑब्जेक्ट बनाया गया है।

B b; 
00331898 lea   ecx,[b] 
0033189B call  B::B (03316A0h) 
003318A0 mov   dword ptr [ebp-4],0 
func(b); 
003318A7 push  ecx 
003318A8 mov   ecx,esp 
003318AA mov   dword ptr [ebp-1Ch],esp 
003318AD lea   eax,[b] 
003318B0 push  eax 
003318B1 call  A::A (0331900h) 
003318B6 mov   dword ptr [ebp-20h],eax 
003318B9 call  func (03317D0h) 

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

  • कोई संबंधित समस्या नहीं^_^