2012-05-25 8 views
17

इस फाइल, first.cpp पर विचार करें, एक वर्ग परिभाषा और उपयोग युक्तएलडी लिंकर एक ही तरीके से एकाधिक कक्षा परिभाषाओं को क्यों अनुमति देता है?

#include <iostream> 

struct Foo 
{ 
    Foo(){ std::cout << "Foo()" << std::endl; } 
    ~Foo(){ std::cout << "~Foo()" << std::endl; } 
}; 

int main(){ 
    Foo f; 
    return 0; 
} 

और एक अन्य, second.cpp, एक परस्पर विरोधी वर्ग परिभाषा युक्त

#include <iostream> 

struct Foo 
{ 
    Foo(); 
    ~Foo(); 
}; 

Foo::~Foo(){ std::cout << "wrong ~Foo()" << std::endl; } 

लिंकर डुप्लिकेट प्रतीकों के बारे में शिकायत जब वहाँ दो हैं एक ही नाम के साथ कार्यों को परिभाषित किया गया है, लेकिन डुप्लिकेट क्लास विधियों वाली इन फ़ाइलों को बिना किसी त्रुटि के संकलित किया गया है।

मैं इन आदेशों के साथ संकलित:

$ g++ -c second.cpp -o second 
$ g++ second first.cpp -o first 

दूसरा g++ कॉल करने के लिए तर्क पुन: क्रम उत्पादन नहीं बदलता है।

और जब first चलाया जाता है, यह उत्पादन होता है:

$ ./first 
Foo() 
wrong ~Foo() 

क्यों लिंकर डुप्लिकेट वर्ग तरीकों अनुमति देता है? यदि यह स्पष्ट रूप से अनुमति है, तो wrong ~Foo() मुद्रित क्यों है?

+0

मैं इसे संकलक के संस्करण पर निर्भर करता है लगता है, लेकिन यह पहले एक यह पाता है लेता है गिरा दिया। – Brady

+0

यह जीसीसी 4.6.1 है। –

+3

यह शायद ऑब्जेक्ट फ़ाइल फ़ंक्शन को पेश करने के तरीके को जोड़ने में फ़ंक्शन के साथ कुछ करना है जहां यह मौजूद है। मुझे लगता है कि अगर आप दूसरे.cpp में एक गैर-इनलाइन संस्करण घोषित करते हैं तो आपको कन्स्ट्रक्टर के साथ एक ही समस्या होगी और यदि दोनों स्रोतों ने इनलाइन फ़ंक्शन को अस्वीकार कर दिया तो समस्या दूर हो जाएगी। – forsvarir

उत्तर

14

फिर, अपरिभाषित व्यवहार। आपके कार्यक्रम में Foo के विनाशक के लिए कई परिभाषाएं हैं, जिसका अर्थ है कि यह ओडीआर का उल्लंघन कर रहा है। कार्यक्रम गलत है और कुछ भी खुश हो सकता है।

लिंकर इसे क्यों नहीं उठाता है? जब कक्षा परिभाषा के अंदर एक फ़ंक्शन परिभाषित किया जाता है, तो यह निश्चित रूप से inline है। कंपाइलर आमतौर पर उन कार्यों को 'कमजोर प्रतीक' के रूप में चिह्नित करते हैं। लिंकर को तब सभी अनुवाद इकाइयां मिलती हैं और प्रतीकों को हल करने की कोशिश करती है। आवश्यकता होने पर कमजोर प्रतीक लिंकर द्वारा छोड़े जाएंगे (यानी यदि प्रतीक पहले से कहीं और परिभाषित किया गया है)।

कार्यक्रम की वास्तविक उत्पादन के रूप में, यह संकलक की तरह दिखता है वास्तव में निर्माता के लिए कॉल इनलाइन नहीं किया है और इस तरह प्रतीक है कि लिंकर (गैर कमजोर एक)

द्वारा छोड़ दिया गया था करने के लिए कार्यावधि में भेजा

क्यों लिंकर डुप्लिकेट विधियों की अनुमति देता है?

क्योंकि सभी कमजोर प्रतीकों (लेकिन अधिकांश में एक) हों (जैसे कि inline)

क्यों, इस मामले में, गलत ~ फू() छपा है?

क्योंकि कॉल inlined नहीं था, और लिंकर कमजोर प्रतीक

+1

किसी कारण से ** अनिर्धारित व्यवहार ** बोल्ड में मुझे सभी गड़बड़ कर देता है। –

+0

@ChetSimpson: मेरा बुरा, यह प्रश्न आज से दूसरे के समान ही है जहां जवाब यह था कि यह यूबी है। यह लगभग वही है, मैंने गलती से माना कि एक ही व्यक्ति रक्तस्राव के किनारे चलने पर जोर दे रहा था, लेकिन अंत में ऐसा लगता है कि अलग-अलग लोगों द्वारा दो प्रश्न पूछे गए थे। –

+0

@@ डेविड-रॉड्रिगेज-ड्राईबीस यह सब अच्छा है, यूबी को हर बार बोल्ड होने की जरूरत है;) –

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

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