2008-09-19 10 views
13

क्या बेस क्लास के कई स्तर कक्षा को धीमा कर रहे हैं? ए डेरिव्स बी डेरिव्स सी डेरिव्स डी डेरिव्स एफ व्युत्पन्न जी, ...क्या बेस क्लास के कई स्तर सी ++ में कक्षा/संरचना को धीमा करते हैं?

क्या एकाधिक विरासत कक्षा को धीमा करती है?

उत्तर

25

गैर-वर्चुअल फ़ंक्शन-कॉलों में सी ++ मंत्र के अनुसार रन-टाइम पर बिल्कुल कोई प्रदर्शन नहीं हुआ है, जिसे आप उपयोग नहीं करते हैं, इसके लिए आपको भुगतान नहीं करना चाहिए। वर्चुअल फ़ंक्शन कॉल में, आप आमतौर पर एक अतिरिक्त पॉइंटर लुकअप के लिए भुगतान करते हैं, इससे कोई फर्क नहीं पड़ता कि विरासत के कितने स्तर हैं, या आपके पास बेस क्लास की संख्या है। बेशक यह सभी कार्यान्वयन परिभाषित है।

संपादित करें: जैसा कि कहीं और उल्लेख किया गया है, कुछ एकाधिक विरासत परिदृश्यों में, कॉल करने से पहले 'इस' सूचक को समायोजन की आवश्यकता है। रेमंड चेन COM वस्तुओं के लिए how this works का वर्णन करता है। असल में, एक ऑब्जेक्ट पर वर्चुअल फ़ंक्शन को कॉल करना जो कई आधारों से प्राप्त होता है, को वर्चुअल कॉल के लिए आवश्यक अतिरिक्त पॉइंटर लुकअप के शीर्ष पर एक अतिरिक्त घटाव और एक jmp निर्देश की आवश्यकता हो सकती है।

+0

जब एकाधिक विरासत का उपयोग किया जाता है, तो आपको इस पॉइंटर के अतिरिक्त ऑफसेट की आवश्यकता होती है जिसे फ़ंक्शन कहा जाता है, http://en.wikipedia.org/wiki/Thunk –

1

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

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

+0

यदि कोई वर्चुअल फ़ंक्शन नहीं है तो क्या होगा? –

+0

फिर इससे कोई फर्क नहीं पड़ता, क्योंकि सभी फ़ंक्शन कॉल संकलित समय पर हल किए जा सकते हैं। अर्थात। संकलक जानता है कि कौन सा फ़ंक्शन कॉल किया जा रहा है, जो एक vtable लुकअप बचाता है। – Thomas

0

हाँ, आप इसे इस तरह संदर्भित कर रहे हैं:

// F is-a E, 
// E is-a D and so on 

A* aObject = new F(); 
aObject->CallAVirtual(); 

तो फिर तुम एक एक प्रकार वस्तु के लिए एक सूचक के साथ काम कर रहे हैं। यह देखते हुए कि आप वर्चुअल फ़ंक्शन को कॉल कर रहे हैं, इसे सही पॉइंटर्स प्राप्त करने के लिए फ़ंक्शन टेबल (vtable) देखना होगा। उस पर कुछ ओवरहेड है, हां।

0

वर्चुअल फ़ंक्शन को कॉल करना एक गैर-वर्चुअल फ़ंक्शन को कॉल करने से थोड़ा धीमा है। हालांकि, मुझे नहीं लगता कि यह आपके विरासत के पेड़ कितना गहरा है।

लेकिन यह कोई फर्क नहीं पड़ता कि आपको सामान्य रूप से चिंतित होना चाहिए।

-1

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

हालांकि, यदि आप बेस क्लास में फ़ंक्शंस को कॉल कर रहे हैं जो इसकी बेस क्लास में फ़ंक्शन कॉल करता है, और इसी तरह, यह प्रदर्शन को प्रभावित कर सकता है।

संक्षेप में, यह इस बात पर निर्भर करता है कि आपने अपने विरासत के पेड़ को कैसे संरचित किया है।

6

[दीप विरासत पदानुक्रम] अनावश्यक जटिलता जोड़कर रखरखाव बोझ को काफी बढ़ाता है, जिससे उपयोगकर्ताओं को कई कक्षाओं के इंटरफेस सीखने के लिए मजबूर किया जाता है, भले ही वे जो कुछ करना चाहते हैं वह एक विशिष्ट व्युत्पन्न वर्ग का उपयोग करें। यह अनावश्यक vtables और उन वर्गों के लिए संकेत जोड़कर मेमोरी उपयोग और प्रोग्राम प्रदर्शन पर भी असर डाल सकता है, जिनकी वास्तव में आवश्यकता नहीं है। यदि आप अक्सर गहरी विरासत पदानुक्रम बनाते हैं, तो आपको यह देखने के लिए अपनी डिजाइन शैली की समीक्षा करनी चाहिए कि आपने इस बुरी आदत को उठाया है या नहीं। दीप पदानुक्रमों की शायद ही कभी आवश्यकता होती है और लगभग कभी भी अच्छी नहीं होती है। और यदि आप उस पर विश्वास नहीं करते हैं लेकिन सोचते हैं कि "ओओ बहुत सारी विरासत के बिना ओओ नहीं है," तो विचार करने के लिए एक अच्छा प्रति उदाहरण [सी ++] मानक लाइब्रेरी है।- Herb Sutter

+5

धन्यवाद, लेकिन यह सवाल का जवाब नहीं देता है। –

2

विभिन्न स्तरों पर वर्चुअल कॉल के बीच कोई गति अंतर नहीं है क्योंकि वे सभी vtable में चले गए हैं (ओवरराइड विधियों के सबसे व्युत्पन्न संस्करणों को इंगित करते हैं)। तो, बुला ((ए *) Inst) - > विधि() जब Instबी का एक उदाहरण है जब Instडी का एक उदाहरण है के रूप में ही भूमि के ऊपर है।

अब, वर्चुअल कॉल गैर-वर्चुअल कॉल से अधिक महंगा है, लेकिन यह पॉइंटर अव्यवस्था की वजह से है और यह नहीं कि वर्ग पदानुक्रम वास्तव में कितना गहरा है।

4
  • एकाधिक वंशानुक्रम एक वर्ग को धीमा करता है?

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

हालांकि, जब एकाधिक वंशानुक्रम शामिल है, वहाँ कभी कभी एक बहुत ही मामूली अतिरिक्त भूमि के ऊपर जब एक आधार वर्ग सूचक के माध्यम से आभासी समारोह बुला है। इस मामले में कुछ कार्यान्वयन आभासी समारोह के बाद से

(static_cast<Base*>(this) == this) 

एक छोटे से thunk है कि 'इस' सूचक समायोजित कर देता है के माध्यम से जाना है वस्तु लेआउट पर निर्भर जरूरी सच नहीं है।

नोट बहुत है कि यह सब, बहुत कार्यान्वयन निर्भर।

देखें Lippman के अध्याय 4.2 "सी ++ ऑब्जेक्ट मॉडल के अंदर" - वर्चुअल सदस्य कार्य/आभासी कार्य एमआई के तहत

2

आभासी कॉल खुद को सामान्य कॉल की तुलना में लग सकता है क्योंकि यह करने के लिए वास्तविक समारोह के पते देखने के लिए है और अधिक समय कर रहे हैं इनलाइन किए जाने वाले की तरह vtable

इसके अतिरिक्त संकलक अनुकूलन से फोन देखने आवश्यकता की वजह से प्रदर्शन करने के लिए कठिन हो सकता है। स्थितियों में, जहां इनलाइन किए जाने वाले काफी उच्च पॉप और धक्का और कूद संचालन

यहाँ ढेर की वजह से भूमि के ऊपर का कारण बन सकता ही संभव नहीं है एक उचित अध्ययन जो भूमि के ऊपर 50% http://www.cs.ucsb.edu/~urs/oocsb/papers/oopsla96.pdf

यहाँ है के रूप में उच्च हो सकता है कहते हैं एक अन्य संसाधन जो आभासी कक्षाओं की एक बड़ी लाइब्रेरी http://keycorner.org/pub/text/doc/kde-slow.txt

एकाधिक उत्तराधिकारों के साथ वर्चुअल कॉल का प्रेषण संकलक विशिष्ट है, इसलिए कार्यान्वयन का भी इस मामले में प्रभाव पड़ेगा।

आधार वर्ग की एक बड़ी नहीं, एक वर्ग वस्तु के भीतर के सभी अन्य घटक कक्षाओं के लिए vtbl ptrs होता की आम तौर पर स्मृति लेआउट होने के अपने विशिष्ट प्रश्न के बारे में।

चेक एक नमूना vtable लेआउट के लिए इस पेज - http://www.codesourcery.com/public/cxx-abi/cxx-vtable-ex.html

तो एक विधि गहरी heierarchy में एक वर्ग द्वारा कार्यान्वित करने के लिए एक फोन अभी भी केवल एक ही अविवेक हो सकता है और नहीं कई indirections के रूप में आपको लगता है लगते हैं। अंत में कॉल करने के लिए सटीक फ़ंक्शन को खोजने के लिए कॉल को कक्षा से कक्षा में नेविगेट करने की आवश्यकता नहीं है।

हालांकि यदि आप विरासत के बजाय संरचना का उपयोग कर रहे हैं तो प्रत्येक पॉइंटर कॉल वर्चुअल कॉल होगा और उस ओवरहेड मौजूद होगा और यदि उस वर्ग में अधिक कंपोजिटियो का उपयोग किया जाता है, तो अधिक वर्चुअल कॉल किए जाएंगे। आपके द्वारा किए गए कॉल की मात्रा के आधार पर एक प्रकार का डिज़ाइन धीमा होगा।

0

Corey Ross द्वारा इंगित किया गया है कि vtable किसी भी पत्ती से प्राप्त कक्षा के लिए संकलन समय पर जाना जाता है, और इसलिए वर्चुअल कॉल की लागत पदानुक्रम की संरचना के बावजूद वास्तव में समान होनी चाहिए।

हालांकि, dynamic_cast के लिए यह नहीं कहा जा सकता है। यदि आप मानते हैं कि आप dynamic_cast को कैसे कार्यान्वित कर सकते हैं, तो मूलभूत दृष्टिकोण में आपके पदानुक्रम के माध्यम से ओ (एन) खोज होगी!

sturct A { int i; }; 
struct B { int j; }; 

struct C : public A, public B { int k ; }; 

// Let's assume that the layout of C is: { [ int i ] [ int j ] [int k ] } 

void foo (C * c) { 
    A * a = c;    // Probably has zero cost 
    B * b = c;    // Compiler needed to add sizeof(A) to 'c' 
    c = static_cast<B*> (b); // Compiler needed to take sizeof(A)' from 'b' 
} 
2

लगभग सभी उत्तर की ओर है या नहीं, आभासी तरीकों में धीमी हो पाएगी और:

एक बहु वंशानुगत पदानुक्रम के मामले में, आप भी पदानुक्रम में विभिन्न वर्गों के बीच परिवर्तित करने के लिए एक छोटे से लागत का भुगतान कर रहे हैं ओपी का उदाहरण है, लेकिन मुझे लगता है कि ओपी बस पूछ रहा है कि क्या कई स्तरों का विरासत धीमा है या नहीं। जवाब निश्चित रूप से नहीं है क्योंकि यह सब C++ में संकलन-समय पर होता है। मुझे संदेह है कि प्रश्न स्क्रिप्ट भाषाओं के अनुभव से प्रेरित है जहां ऐसे विरासत ग्राफ गतिशील हो सकते हैं, और उस स्थिति में, यह संभावित रूप से धीमा हो सकता है।

1

एक गहरे विरासत के पेड़ में गैर-तुच्छ कन्स्ट्रक्टर होने से ऑब्जेक्ट सृजन धीमा हो सकता है, जब बच्चे के प्रत्येक सृजन में सभी मूल रचनाकारों को आधार तक सभी तरह से कॉल किया जाता है।

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