मैंने एक समान question से पहले इंटरफ़ेस चर के बारे में बहुत पहले नहीं पूछा था।निहित इंटरफेस चर के संकलक उपचार दस्तावेज है?
इस प्रश्न का स्रोत मेरे कोड में एक बग था क्योंकि मुझे संकलक द्वारा बनाए गए एक अंतर्निहित इंटरफ़ेस चर के अस्तित्व के बारे में पता नहीं था। इस चर को अंतिम रूप दिया गया था जब इसकी प्रक्रिया समाप्त हो गई थी। इसके बदले में चर के जीवनकाल की वजह से एक बग का कारण बन गया था जो मैंने अनुमान लगाया था।
program ImplicitInterfaceLocals;
{$APPTYPE CONSOLE}
uses
Classes;
function Create: IInterface;
begin
Result := TInterfacedObject.Create;
end;
procedure StoreToLocal;
var
I: IInterface;
begin
I := Create;
end;
procedure StoreViaPointerToLocal;
var
I: IInterface;
P: ^IInterface;
begin
P := @I;
P^ := Create;
end;
begin
StoreToLocal;
StoreViaPointerToLocal;
end.
StoreToLocal
बस के रूप में आप कल्पना कर सकते हैं संकलित किया गया है:
अब, मैं संकलक से कुछ दिलचस्प व्यवहार को वर्णन करने के लिए एक सरल परियोजना है। स्थानीय चर I
, फ़ंक्शन का परिणाम Create
पर एक अंतर्निहित var
पैरामीटर के रूप में पारित किया गया है। StoreToLocal
के लिए साफ-सुथरा परिणाम एक ही कॉल में IntfClear
पर होता है। वहां कोई आश्चर्य नहीं है।
हालांकि, StoreViaPointerToLocal
का अलग-अलग व्यवहार किया जाता है। कंपाइलर एक अंतर्निहित स्थानीय चर बनाता है जो यह Create
तक जाता है। जब Create
रिटर्न, P^
पर असाइनमेंट किया जाता है। यह इंटरफ़ेस के संदर्भ वाले दो स्थानीय चर के साथ दिनचर्या छोड़ देता है। StoreViaPointerToLocal
के लिए साफ-सुथरा परिणाम दो कॉल में IntfClear
पर है।
StoreViaPointerToLocal
के लिए
संकलित कोड इस तरह है:
ImplicitInterfaceLocals.dpr.24: begin
00435C50 55 push ebp
00435C51 8BEC mov ebp,esp
00435C53 6A00 push $00
00435C55 6A00 push $00
00435C57 6A00 push $00
00435C59 33C0 xor eax,eax
00435C5B 55 push ebp
00435C5C 689E5C4300 push $00435c9e
00435C61 64FF30 push dword ptr fs:[eax]
00435C64 648920 mov fs:[eax],esp
ImplicitInterfaceLocals.dpr.25: P := @I;
00435C67 8D45FC lea eax,[ebp-$04]
00435C6A 8945F8 mov [ebp-$08],eax
ImplicitInterfaceLocals.dpr.26: P^ := Create;
00435C6D 8D45F4 lea eax,[ebp-$0c]
00435C70 E873FFFFFF call Create
00435C75 8B55F4 mov edx,[ebp-$0c]
00435C78 8B45F8 mov eax,[ebp-$08]
00435C7B E81032FDFF call @IntfCopy
ImplicitInterfaceLocals.dpr.27: end;
00435C80 33C0 xor eax,eax
00435C82 5A pop edx
00435C83 59 pop ecx
00435C84 59 pop ecx
00435C85 648910 mov fs:[eax],edx
00435C88 68A55C4300 push $00435ca5
00435C8D 8D45F4 lea eax,[ebp-$0c]
00435C90 E8E331FDFF call @IntfClear
00435C95 8D45FC lea eax,[ebp-$04]
00435C98 E8DB31FDFF call @IntfClear
00435C9D C3 ret
मैं क्यों संकलक इस कर रही है के रूप में अनुमान लगा सकते हैं। जब यह साबित हो सकता है कि परिणाम परिवर्तक को असाइन करने से अपवाद नहीं बढ़ेगा (यानी यदि चर एक स्थानीय है) तो यह परिणाम चर का उपयोग सीधे करता है। अन्यथा यह एक निहित स्थानीय का उपयोग करता है और फ़ंक्शन वापस लौटने के बाद इंटरफ़ेस की प्रतिलिपि बनाता है जिससे यह सुनिश्चित किया जाता है कि हम अपवाद के मामले में संदर्भ को रिसाव नहीं करते हैं।
लेकिन मुझे दस्तावेज़ में इसका कोई विवरण नहीं मिल रहा है। यह महत्वपूर्ण है क्योंकि इंटरफ़ेस जीवनकाल महत्वपूर्ण है और एक प्रोग्रामर के रूप में आपको अवसर पर इसे प्रभावित करने में सक्षम होना चाहिए।
तो, क्या किसी को पता है कि इस व्यवहार का कोई दस्तावेज है या नहीं? यदि नहीं, तो क्या इसका कोई और ज्ञान नहीं है? उदाहरण फ़ील्ड कैसे प्रबंधित किए जाते हैं, मैंने अभी तक यह जांच नहीं की है। निस्संदेह मैं इसे अपने लिए बाहर कर सकता हूं लेकिन मैं एक और औपचारिक वक्तव्य की तलाश में हूं और हमेशा परीक्षण और त्रुटि द्वारा कार्यान्वित कार्यान्वयन विवरण पर भरोसा करना पसंद करता हूं।
अद्यतन 1
रेमी के सवाल का जवाब करने के लिए, यह मेरे लिए मायने रखता है जब मैं एक और अंतिम रूप दिए जाने से बाहर ले जाने से पहले इंटरफ़ेस के पीछे वस्तु को अंतिम रूप देने की जरूरत है।
begin
AcquirePythonGIL;
try
PyObject := CreatePythonObject;
try
//do stuff with PyObject
finally
Finalize(PyObject);
end;
finally
ReleasePythonGIL;
end;
end;
जैसा लिखा है यह ठीक है। लेकिन असली कोड में मेरा दूसरा निहित स्थानीय था जिसे जीआईएल जारी करने के बाद अंतिम रूप दिया गया था और उस पर हमला किया गया था। मैंने एक अलग विधि में अधिग्रहण/रिलीज जीआईएल के अंदर कोड निकालने से समस्या हल की और इस प्रकार इंटरफ़ेस चर के दायरे को संकुचित कर दिया।
पता नहीं क्यों यह डाउनवॉट किया गया था, इसके अलावा सवाल वास्तव में जटिल है। मेरे सिर पर रास्ता होने के लिए ऊपर उठाया। मुझे पता है कि वास्तव में इस तरह के आर्केनम के परिणामस्वरूप एक साल पहले मैंने एक ऐप में कुछ सूक्ष्म संदर्भ गिनती बग का परिणाम दिया था। हमारे सबसे अच्छे गीकों में से एक ने इसे समझने में घंटों बिताए। अंत में हमने इसके आसपास काम किया लेकिन कभी समझ नहीं आया कि संकलक कैसे काम करने का इरादा रखता था। –
जब आप संदर्भ-गिनती इंटरफेस के साथ काम करते हैं तो आपको यह नहीं मानना चाहिए कि कोई अन्य ग्राहक नहीं है (आपके मामले में कंपाइलर) जिसमें उनके स्वयं के इंटरफ़ेस संदर्भ हैं। यदि सभी ग्राहक सही ढंग से 'AddRef'/'रिलीज' करते हैं, तो सभी को ठीक काम करना चाहिए। अन्यथा यह एक बग है (आपकी बग जब से मुझे लगता है कि संकलक सही संदर्भ गिनती करता है)। – kludg
@ सर्ग कंपाइलर ने इसका संदर्भ पूरी तरह से गिन रहा था। समस्या यह थी कि एक अतिरिक्त चर था जिसमें एक संदर्भ था जिसे मैं नहीं देख सका। मैं जो जानना चाहता हूं वह इतना अतिरिक्त, छुपा, संदर्भ लेने के लिए संकलक को उत्तेजित करता है। –