2015-02-28 6 views
21

मैं का उपयोग कर निम्नलिखित सरल सी ++ कोड संकलित करने के लिए कोशिश कर रहा हूँ बजना-3.5:बजना: कोई आउट-ऑफ-लाइन आभासी विधि परिभाषाओं (शुद्ध सार सी ++ वर्ग)

test.h:

class A 
{ 
    public: 
    A(); 
    virtual ~A() = 0; 
}; 

test.cc:

#include "test.h" 

A::A() {;} 
A::~A() {;} 

आदेश है कि मैं इस संकलन के लिए उपयोग (लिनक्स, uname -r: 3.16.0-4-amd64):

$clang-3.5 -Weverything -std=c++11 -c test.cc 

और त्रुटि है कि मैं:

./test.h:1:7: warning: 'A' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit [-Wweak-vtables] 

कोई संकेत क्यों यह एक चेतावनी उत्सर्जित करती है? आभासी विनाशक बिल्कुल रेखांकित नहीं है। काफी विपरीत, test.cc में प्रदान की गई एक बाहरी परिभाषा है। मुझे यहां क्या समझ नहीं आ रहा है?

संपादित

मुझे नहीं लगता कि इस सवाल का डुप्लिकेट है है: What is the meaning of clang's -Wweak-vtables? के रूप में फ़िलिप Roséen का सुझाव दिया। मेरे प्रश्न में मैं विशेष रूप से शुद्ध अमूर्त कक्षाओं का उल्लेख करता हूं (सुझाए गए डुप्लिकेट में उल्लिखित नहीं)। मुझे पता है कि -Wweak-vtables गैर सार वर्गों के साथ काम करता है और मैं इसके साथ ठीक हूँ। मेरे उदाहरण में मैं कार्यान्वयन फ़ाइल में विनाशक (जो शुद्ध सार है) परिभाषित करता हूं। इससे क्लैंग को -Wweak-vtables के साथ भी किसी भी त्रुटि को उत्सर्जित करने से रोका जाना चाहिए।

+0

@ gha.st वास्तव में, लेकिन क्या अंतर नहीं करता है? एक जटिल परिसर वर्ग को लागू करते समय मैं इस समस्या में आया, लेकिन यह यहां अप्रासंगिक है। उपरोक्त कोड अभी भी ठीक होना चाहिए, है ना? –

+0

क्या यह [यह अन्य प्रश्न] (http://stackoverflow.com/q/28788353/2069064) का सटीक डुप्ली नहीं है जिसे आपने 3 घंटे बाद पूछा था? – Barry

+0

@ बैरी मुझे लगता है कि यह दोनों का बेहतर सवाल है, इसलिए यह वह है जिसे मैंने बाउंस किया था। दूसरा सवाल बताता है कि उस समय पूछने के समय, यह एक दूसरे के डुप्ली के रूप में बंद कर दिया गया था, लेकिन बाद में इसे फिर से खोल दिया गया। – Oktalist

उत्तर

8

हम प्रत्येक अनुवाद इकाई में vtable नहीं रखना चाहते हैं। इसलिए अनुवाद इकाइयों का कुछ आदेश होना चाहिए, जैसे कि हम तब कह सकते हैं कि हम "प्रथम" अनुवाद इकाई में vtable डालते हैं। यदि यह आदेश अपरिभाषित है, तो हम चेतावनी को छोड़ देते हैं।

आपको Itanium CXX ABI में उत्तर मिल गया। (5.2.3) आभासी तालिकाओं के बारे में अनुभाग में आप पाते हैं:

एक वर्ग के लिए आभासी मेज, एक ही वस्तु उसके प्रमुख समारोह की परिभाषा युक्त में उत्सर्जित होता है पहली गैर शुद्ध आभासी समारोह यानी कि है कक्षा परिभाषा के बिंदु पर इनलाइन नहीं है। यदि कोई महत्वपूर्ण कार्य नहीं है, तो यह हर जगह इस्तेमाल किया जाता है। उत्सर्जित आभासी तालिका में वर्ग के लिए पूर्ण आभासी तालिका समूह, उप-प्रोजेक्ट के लिए आवश्यक कोई भी नया निर्माण वर्चुअल टेबल और कक्षा के लिए VTT शामिल है। वे एक COMDAT समूह में उत्सर्जित होते हैं, वर्चुअल टेबल को पहचानने वाले प्रतीक के रूप में नामित किया जाता है। ध्यान दें कि यदि कुंजी फ़ंक्शन कक्षा परिभाषा में इनलाइन घोषित नहीं किया गया है, लेकिन बाद में इसकी परिभाषा हमेशा इनलाइन घोषित की जाती है, तो यह परिभाषा वाले प्रत्येक ऑब्जेक्ट में उत्सर्जित की जाएगी।
नोट: सार में, शुद्ध वर्चुअल विनाशक को मुख्य कार्य के रूप में उपयोग किया जा सकता है, क्योंकि यह शुद्ध होना चाहिए, भले ही यह शुद्ध हो। हालांकि, एबीआई समिति को इस तथ्य का एहसास नहीं हुआ जब तक कि मुख्य कार्य के विनिर्देशन पूरा नहीं हो गया; इसलिए शुद्ध वर्चुअल विनाशक महत्वपूर्ण कार्य नहीं हो सकता है।

दूसरा अनुभाग आपके प्रश्न का उत्तर है। एक शुद्ध वर्चुअल विनाशक कोई महत्वपूर्ण कार्य नहीं है। इसलिए, यह स्पष्ट नहीं है कि vtable कहां रखा जाए और इसे हर जगह रखा जाए। नतीजतन हमें चेतावनी मिलती है।

आपको यह स्पष्टीकरण Clang source documentation में भी मिलेगा।

तो विशेष रूप से चेतावनी: आप चेतावनी मिल जाएगा जब अपने आभासी कार्यों के सभी निम्नलिखित श्रेणियों में से एक से संबंधित हैं:

  1. inline वर्ग परिभाषा A::x() के लिए निर्दिष्ट किया जाता है।

    struct A { 
        inline virtual void x(); 
        virtual ~A() { 
        } 
    }; 
    void A::x() { 
    } 
    
  2. बी :: एक्स() वर्ग परिभाषा इनलाइन है।

    struct B { 
        virtual void x() { 
        } 
        virtual ~B() { 
        } 
    }; 
    
  3. सी :: एक्स() है शुद्ध आभासी

    struct C { 
        virtual void x() = 0; 
        virtual ~C() { 
        } 
    }; 
    
  4. (से संबंध रखता है 3.) आप एक शुद्ध आभासी नाशक

    struct D { 
        virtual ~D() = 0; 
    }; 
    D::~D() { 
    } 
    

    इस मामले में है, आदेश परिभाषित किया जा सकता है, क्योंकि विनाशक को परिभाषित किया जाना चाहिए, फिर भी, परिभाषा के अनुसार, अभी भी कोई "पहली" अनुवाद इकाई नहीं है।

अन्य सभी मामलों के लिए, मुख्य कार्य पहले आभासी समारोह है कि इन श्रेणियों में से एक के लिए फिट नहीं करता है, और vtable अनुवाद इकाई जहां मुख्य कार्य परिभाषित किया गया है में रखा जाएगा।

3

मैं एक छोटी सी आभासी नाशक को लागू करने के बजाय उसे शुद्ध आभासी छोड़ने समाप्त हो गया।

तो बजाय

class A { 
public: 
    virtual ~A() = 0; 
}; 

मैं

class A { 
public: 
    virtual ~A(); 
}; 

का उपयोग फिर एक .cpp फ़ाइल में तुच्छ नाशक लागू:

A::~A() 
{} 

यह प्रभावी रूप से सीपीपी को vtable पिंस फ़ाइल, एकाधिक अनुवाद इकाइयों (ऑब्जेक्ट्स) में इसे आउटपुट करने के बजाय, और सफलतापूर्वक -Wweak-vtables चेतावनी से बचाता है जी।

+2

आपका सुझाव इस प्रकार सरलीकृत किया जा सकता है: ** ** शुद्ध सार वर्गों का उपयोग न करें और आपको चेतावनी नहीं मिलेगी। यह मेरे प्रश्न से कैसे संबंधित है? यह स्पष्ट है कि लेखक का इरादा वास्तव में ** ** शुद्ध सार वर्ग का उपयोग करना है। –

+1

यह अभी भी अवधारणात्मक रूप से शुद्ध सार आधार वर्ग है, लेकिन vtable को डुप्लिकेट करने के दुष्प्रभाव के बिना। –

+0

मैंने पहली वाक्य में यही कहा था। मैं एक संभावित समाधान प्रदान कर रहा हूं। मैंने इस प्रश्न के आपके दोबारा दो संभावित समाधानों का लंबा विवरण प्रदान किया: http://stackoverflow.com/questions/28788353/clang-wweak-vtables-and-pure-abstract-class - जहां मैंने अक्षम करने का एक उदाहरण शामिल किया चेतावनी अगर आप इसे शुद्ध सार रखना चाहते हैं। –

10

एक पल के लिए, हम शुद्ध आभासी कार्यों के बारे में भूल जाते हैं और समझने के लिए कैसे संकलक कि एक बहुरूपी वर्ग की घोषणा में शामिल सभी अनुवाद इकाइयों में vtable उत्सर्जन से बच सकते हैं कोशिश करते हैं।

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

तो, इस अनुकूलन की कुंजी वर्चुअल विधि का चयन करना है जैसे संकलक गारंटी दे सकता है कि उसे कुछ अनुवाद इकाई में उस विधि की एक (एकल) परिभाषा का सामना करना पड़ेगा।

अब, यदि कक्षा घोषणा में शुद्ध वर्चुअल फ़ंक्शन शामिल हैं तो क्या होगा? एक प्रोग्रामर शुद्ध वर्चुअल फ़ंक्शन के लिए कार्यान्वयन प्रदान कर सकता है लेकिन वह के लिए बाध्य नहीं है! इसलिए शुद्ध वर्चुअल फ़ंक्शंस उम्मीदवार वर्चुअल विधियों की सूची से संबंधित नहीं है, जिससे संकलक प्रतिनिधि का चयन कर सकता है।

लेकिन एक अपवाद है - एक शुद्ध वर्चुअल विनाशक! यदि आप इसे से अन्य वर्गों प्राप्त करने के लिए नहीं जा रहे हैं

  1. एक सार वर्ग मतलब नहीं है:

    एक शुद्ध आभासी नाशक एक विशेष मामला है।

  2. एक उप-वर्ग 'विनाशक हमेशा बेस क्लास' विनाशक को बुलाता है।
  3. वर्चुअल विनाशक के साथ कक्षा से प्राप्त कक्षा का विनाश स्वचालित रूप से वर्चुअल फ़ंक्शन होता है।
  4. प्रोग्राम सभी वस्तुओं के सभी वर्चुअल फ़ंक्शंस, जो प्रोग्राम ऑब्जेक्ट बनाता है, आमतौर पर अंतिम निष्पादन योग्य (वर्चुअल फ़ंक्शंस सहित) को अप्रयुक्त रहने के लिए स्थिर रूप से साबित किया जा सकता है, हालांकि पूर्ण प्रोग्राम के स्थिर विश्लेषण की आवश्यकता होगी)।
  5. इसलिए शुद्ध वर्चुअल विनाशक उपयोगकर्ता द्वारा प्रदत्त परिभाषा है।

इस प्रकार, प्रश्न के उदाहरण में क्लैंग की चेतावनी अवधारणात्मक रूप से उचित नहीं है।

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

+0

शुद्ध वर्चुअल विनाशकों पर भी [हर्ब सटर के विचार] (http://www.gotw.ca/gotw/031.htm) देखें। एकमात्र ऐसी स्थिति जहां मैं एक आभासी विध्वंसक के रूप में उपयोगी होने के लिए एक शुद्ध वर्चुअल विनाशक की कल्पना कर सकता हूं, जब आप पॉइंटर्स के साथ काम करने के लिए 'dynamic_cast' का उपयोग करके पॉइंटर्स का संग्रह चाहते हैं। –

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