2013-08-25 9 views
8

inlined किया जा सकता है, तो मैं इस तरह एक वर्ग को परिभाषित:आभासी कार्यों

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

यह मतलब यह है कि कि आभासी नाशक और func inlined रहे

+0

यदि आप इसके बारे में सोचते हैं, तो वर्चुअल फ़ंक्शंस को रेखांकित करना वास्तव में समझ में नहीं आता है। एकमात्र मामला मैं देख सकता हूं कि यदि आप संकलन समय पर प्रकार जानते हैं, लेकिन फिर भी मुझे यकीन नहीं है कि एक कंपाइलर अनुकूलन करेगा। – Borgleader

+0

http://stackoverflow.com/questions/733737/are-inline-virtual-functions-really-a-non-sense?rq=1 – Mat

+0

@ बोर्गलीडर: वे करते हैं, जब वे कर सकते हैं।हालांकि पॉलिमॉर्फिक वस्तुओं के निर्माण और विनाश के संबंध में सी ++ भाषा में जटिल नियमों के कारण कोई संकलक वास्तव में अच्छा नहीं है। इसके अलावा, चूंकि सामान्य रूप से कोई जेटिंग नहीं है, इसलिए परिस्थितियों का बहुत सबसेट जहां इसे किया जा सकता है सीमित है। –

उत्तर

10

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

A* a = new B; 
a->func(); 

इस मामले में संकलक निर्धारित कर सकते हैं कि एक B वस्तु को a अंक, और इस प्रकार गतिशील प्रेषण के बिना func() का सही संस्करण कहते हैं। गतिशील प्रेषण की आवश्यकता के बिना, func() को तब रेखांकित किया जा सकता है। बेशक, क्या संकलन संबंधित विश्लेषण करते हैं, इसके संबंधित कार्यान्वयन पर निर्भर करता है।

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

+3

वर्चुअल फ़ंक्शन ('a-> ए :: func() ') के लिए एक गैर वर्चुअल कॉल एक और कुछ स्पष्ट उदाहरण है जहां आम तौर पर इनलाइनिंग काम करता है। – hvd

+0

मैं @Mat दिए गए लिंक को देखता हूं, ऐसा लगता है कि रेखांकित आभासी विनाशक समझ में आता है, लेकिन मैं अभी भी थोड़ा उलझन में हूं कि कैसे विनाशकों को – Ghostblade

+2

* में रेखांकित किया गया है * जब संकलक साबित कर सकता है कि स्थिर प्रकार गतिशील प्रकार से मेल खाता है *: यह वास्तव में है उससे अधिक जटिल। 'बेस * बी = नया व्युत्पन्न {} पर विचार करें; बी-> func(); ', यहां कॉल को रेखांकित किया जा सकता है यदि संकलक इतना समझने के लिए पर्याप्त स्मार्ट है कि 'बी' का गतिशील प्रकार आवश्यक रूप से' व्युत्पन्न 'है। क्लैंग इतना स्मार्ट कंपाइलर है। –

4

हां, और कई तरीकों से। आप devirtualizationin this email के कुछ उदाहरण देख सकते हैं, मैंने लगभग 2 साल पहले क्लैंग मेलिंग सूची में भेजा था।

सभी अनुकूलन की तरह, यह विकल्प को खत्म करने के लिए कंपाइलर क्षमताओं के लंबित है: यदि यह साबित कर सकता है कि वर्चुअल कॉल को हमेशा Derived::func में हल किया जाता है तो यह इसे सीधे कॉल कर सकता है।

विभिन्न स्थितियों रहे हैं, हमें अर्थ सबूतों के साथ पहले शुरू करते हैं:

  • SomeDerived& d जहां SomeDerivedfinal है सभी विधि के devirtualization करने की अनुमति देता कॉल
  • SomeDerived& d, जहां foofinal है भी की devirtualization की अनुमति देता है यह विशेष कॉल

फिर, ऐसी स्थितियां हैं जहां वस्तु के गतिशील प्रकार पता:

  • SomeDerived d; =>d के गतिशील प्रकार जरूरी है SomeDerived
  • SomeDerived d; Base& b; =>b के गतिशील प्रकार जरूरी SomeDerived

उन 4 devirtualization है परिस्थितियों को आम तौर पर कंपाइलर फ्रंट एंड द्वारा हल किया जाता है क्योंकि उन्हें भाषा अर्थशास्त्र के बारे में मौलिक ज्ञान की आवश्यकता होती है। मैं प्रमाणित कर सकता हूं कि सभी 4 क्लैंग में लागू किए गए हैं, और मुझे लगता है कि वे जीसीसी में भी लागू किए गए हैं।

struct Base { virtual void foo() = 0; }; 
struct Derived: Base { virtual void foo() { std::cout << "Hello, World!\n"; }; 

void opaque(Base& b); 
void print(Base& b) { b.foo(); } 

int main() { 
    Derived d; 

    opaque(d); 

    print(d); 
} 

यहां तक ​​कि यहां हालांकि यह स्पष्ट है कि foo करने के लिए कॉल करने के लिए Derived::foo हल हो गई है, बजना/LLVM अनुकूलित नहीं होगा:

हालांकि, वहाँ है, जहां यह टूट जाती है स्थितियों के बहुत सारे हैं। मुद्दा यह है कि:

  • बजना (सामने के अंत) इनलाइन किए जाने वाले प्रदर्शन नहीं करता, इस प्रकार यह द्वारा print(d) को बदल नहीं सकते और कॉल
  • LLVM (बैक-एंड) devirtualize भाषा के शब्दों को नहीं जानता है , द्वारा print(d) बदलने के बाद इस प्रकार भी यह मानता है कि d की आभासी सूचक (जिसकी परिभाषा अपारदर्शी है, के रूप में नाम का तात्पर्य)

मैं बजना और LLVM मैली के प्रयासों पर पालन किया है opaque द्वारा बदला जा सकता था एनजी सूची के रूप में डेवलपर्स के दोनों सेटों के बारे में जानकारी के नुकसान और एलएलवीएम को बताने के लिए क्लैंग कैसे प्राप्त करें: "यह ठीक है" लेकिन दुर्भाग्यवश यह मुद्दा गैर-तुच्छ है और अभी तक हल नहीं किया गया है ... इस प्रकार आधा assed devirtualization सभी स्पष्ट मामलों को आजमाएं और प्राप्त करें, और कुछ स्पष्ट नहीं हैं (भले ही, सम्मेलन द्वारा, फ्रंट एंड वह जगह नहीं है जहां आप उन्हें लागू करते हैं)।


संदर्भ के लिए, बजना में devirtualization के लिए कोड एक समारोह canDevirtualizeMemberFunctionCalls बुलाया में CGExprCXX.cpp में पाया जा सकता। यह केवल ~ 64 लाइनें लंबी है (अभी अभी) और पूरी तरह से टिप्पणी की।

+0

+1। – Surt

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