मैंने कोड को थोड़ा सा बदलने के लिए थोड़ा सा बदल दिया, और मेरे लिए ऐसा लगता है कि यह vtable को छोड़ रहा है, लेकिन मैं यह बताने के लिए पर्याप्त विशेषज्ञ नहीं हूं।
g++ -g -S -O0 -fverbose-asm virt.cpp
as -alhnd virt.s > virt.base.asm
g++ -g -S -O6 -fverbose-asm virt.cpp
as -alhnd virt.s > virt.opt.asm
और दिलचस्प बिट्स 'ऑप्ट' की तरह मेरे लिए देखने के संस्करण: मुझे यकीन है कि कुछ टिप्पणीकारों मुझे सेट हो जाएगा सही हालांकि :)
struct A {
virtual int foo() { return 1; }
};
struct B : public A {
virtual int foo() { return 2; }
};
int useIt(A* a) {
return a->foo();
}
int main()
{
B* b = new B();
return useIt(b);
}
मैं तो इस कोड को विधानसभा के लिए इस तरह परिवर्तित कर रहा हूँ vtable छोड़ रहा है। ऐसा लगता है कि यह vtable बनाने है, लेकिन इसे प्रयोग नहीं ..
ऑप्ट एएसएम में:
9:virt.cpp **** int useIt(A* a) {
89 .loc 1 9 0
90 .cfi_startproc
91 .LVL2:
10:virt.cpp **** return a->foo();
92 .loc 1 10 0
93 0000 488B07 movq (%rdi), %rax # a_1(D)->_vptr.A, a_1(D)->_vptr.A
94 0003 488B00 movq (%rax), %rax # *D.2259_2, *D.2259_2
95 0006 FFE0 jmp *%rax # *D.2259_2
96 .LVL3:
97 .cfi_endproc
और आधार।उसी के एएसएम संस्करण:
9:virt.cpp **** int useIt(A* a) {
88 .loc 1 9 0
89 .cfi_startproc
90 0000 55 pushq %rbp #
91 .LCFI6:
92 .cfi_def_cfa_offset 16
93 .cfi_offset 6, -16
94 0001 4889E5 movq %rsp, %rbp #,
95 .LCFI7:
96 .cfi_def_cfa_register 6
97 0004 4883EC10 subq $16, %rsp #,
98 0008 48897DF8 movq %rdi, -8(%rbp) # a, a
10:virt.cpp **** return a->foo();
99 .loc 1 10 0
100 000c 488B45F8 movq -8(%rbp), %rax # a, tmp64
101 0010 488B00 movq (%rax), %rax # a_1(D)->_vptr.A, D.2263
102 0013 488B00 movq (%rax), %rax # *D.2263_2, D.2264
103 0016 488B55F8 movq -8(%rbp), %rdx # a, tmp65
104 001a 4889D7 movq %rdx, %rdi # tmp65,
105 001d FFD0 call *%rax # D.2264
11:virt.cpp **** }
106 .loc 1 11 0
107 001f C9 leave
108 .LCFI8:
109 .cfi_def_cfa 7, 8
110 0020 C3 ret
111 .cfi_endproc
लाइन 93 पर हम टिप्पणी में देखें: _vptr.A
जो मैं यकीन है कि इसका मतलब यह वास्तविक मुख्य कार्य में एक vtable देखने कर रहा है, तथापि, कर रहा हूँ, यह करने में सक्षम हो रहा है जवाब का अनुमान है और यहां तक कि कि useIt कोड फोन नहीं करता है:
16:virt.cpp **** return useIt(b);
17:virt.cpp **** }
124 .loc 1 17 0
125 0015 B8020000 movl $2, %eax #,
जो मुझे लगता है कि सिर्फ कह रहा है, हम जानते हैं कि हम वापसी करने वाले 2, बस eax में रख देता है। (मैं कार्यक्रम को फिर से चलाने के लिए कह रहा हूं 200, और उस लाइन को अपडेट किया गया जैसा कि मैं उम्मीद करता हूं)।
अतिरिक्त बिट
तो मैं कार्यक्रम को जटिल थोड़ा अधिक:
:
struct A {
int valA;
A(int value) : valA(value) {}
virtual int foo() { return valA; }
};
struct B : public A {
int valB;
B(int value) : valB(value), A(0) {}
virtual int foo() { return valB; }
};
int useIt(A* a) {
return a->foo();
}
int main()
{
A* a = new A(100);
B* b = new B(200);
int valA = useIt(a);
int valB = useIt(a);
return valA + valB;
}
इस संस्करण में, useIt कोड निश्चित रूप से अनुकूलित विधानसभा में vtable का उपयोग करता है
13:virt.cpp **** int useIt(A* a) {
89 .loc 1 13 0
90 .cfi_startproc
91 .LVL2:
14:virt.cpp **** return a->foo();
92 .loc 1 14 0
93 0000 488B07 movq (%rdi), %rax # a_1(D)->_vptr.A, a_1(D)->_vptr.A
94 0003 488B00 movq (%rax), %rax # *D.2274_2, *D.2274_2
95 0006 FFE0 jmp *%rax # *D.2274_2
96 .LVL3:
97 .cfi_endproc
इस बार, मुख्य कार्य इनलाइन useIt
की एक प्रति, लेकिन वास्तव में vtable लुकअप करता है।
के बारे में क्या C++ 11 और 'अंतिम' कीवर्ड?
तो मैं करने के लिए एक लाइन बदल:
virtual int foo() override final { return valB; }
और संकलक लाइन के लिए:
g++ -std=c++11 -g -S -O6 -fverbose-asm virt.cpp
में सोच रही थी कि संकलक इसे अंतिम ओवरराइड है कि कह रहा, इसे छोड़ करने की अनुमति होगी शायद vtable।
यह अभी भी vtable का उपयोग करता है।
तो मेरी सैद्धांतिक जवाब होगा:
- मुझे नहीं लगता कि किसी भी स्पष्ट, "vtable का उपयोग नहीं करते" अनुकूलन कर रहे हैं। (मैंने vtable और virt के लिए g ++ manpage के माध्यम से खोज की और जैसा कुछ भी नहीं मिला)।
- लेकिन जी ++ के साथ -6, एक सरल प्रोग्राम पर बहुत अनुकूलन कर सकता है जिसमें स्पष्ट स्थिरांक बिंदु के साथ जहां यह परिणाम की भविष्यवाणी कर सकता है और कॉल को पूरी तरह से छोड़ सकता है।
- हालांकि, एक बार चीजें जटिल हो जाती हैं (वास्तविक पढ़ें) यह निश्चित रूप से vtable लुकअप कर रही है, हर बार जब आप वर्चुअल फ़ंक्शन को कॉल करते हैं।
क्या आप अनुकूलित करने की कोशिश कर रहे हैं (अपना समय कम्पाइलर नौकरी बर्बाद न करें)। या आप एक तकनीक चाहते हैं कि बस बी के संस्करण को foo() के कॉल करें? –
आपको वास्तव में चिंता नहीं करनी चाहिए कि प्रेषण प्रत्यक्ष होगा या एक vtable के माध्यम से जाना होगा। अधिकांश परिदृश्यों में, वर्चुअल विधि तालिका प्रेषण का प्रदर्शन पर कभी भी महत्वपूर्ण प्रभाव नहीं पड़ता है। –