我遇到了問題,某些VCL控件偶爾在被銷燬時觸發事件,導致處理程序以已經被銷燬的子分類形式被調用(例如,控件被析構函數)VCL事件在銷燬期間
這是一個由(第三方)控制問題的契約違約,我應該拋棄每個事件處理程序與「如果(開放)」警衛,或應該這由其他一些機制來處理。我可能天真地認爲,自動封閉會自動取消註冊,這與常規虛擬功能的工作原理有些類似。
我遇到了問題,某些VCL控件偶爾在被銷燬時觸發事件,導致處理程序以已經被銷燬的子分類形式被調用(例如,控件被析構函數)VCL事件在銷燬期間
這是一個由(第三方)控制問題的契約違約,我應該拋棄每個事件處理程序與「如果(開放)」警衛,或應該這由其他一些機制來處理。我可能天真地認爲,自動封閉會自動取消註冊,這與常規虛擬功能的工作原理有些類似。
__published
閉包不作任何類型的保證,閉包只是一個指向類實例和函數的指針。但是VCL中還有其他的機制。
通常,在開發依賴於其他組件的組件時,確保在組件被刪除時清除任何內部引用是一種很好的做法。在VCL中,可以通過TComponent
中的免費通知來實現此目的。
如果您依賴的組件具有不同的所有者且不在表單上,那麼您必須註冊組件以接收這些通知。您通過FreeNotification
函數執行此操作(請記住在刪除通知組件時再次取消註冊組件,此用途RemoveFreeNotification
)。無論何時將控件添加到與此組件相同的表單(或所有者),將調用功能Notification
,並引用添加或刪除的組件以及執行的操作。
因此,您只需覆蓋Notification
函數,請記得調用父函數。重載函數看起來是這樣的:
void __fastcall TMyComponent::Notification(TComponent* AComponent, TOperation Operation)
{
if (Operation == opRemove && AComponent == interestingComponent)
{
this->interestingComponent = NULL;
}
inherited::Notification(AComponent, Operation);
}
如果這是一個第三方的控制當然就應該確保這一點,並確保有dangling pointers,由於組件被釋放,如果由於某種原因,忘了你必須添加該功能,無論是通過子類別還是按照您所述的方式重置事件。如果這是你自己的組件,那麼你應該確保做到這一點。
您的越野車控制系統的「所有者」屬性設置是否正確?默認情況下,表單擁有其上的所有控件,它們的「Owner」屬性指向TForm實例,並且此表單負責釋放所有擁有的控件。如果通過IDE窗體設計器設計窗體,這就是工作方式。如果您手動創建控件,則必須通過構造函數提供「所有者」屬性。檢查您是否傳遞正確的表單作爲「所有者」。另外,如果你有自定義控件的源代碼,建立在TControl的頂部,檢查它們的構造函數是否正確地將「Owner」屬性傳遞給底層的TControl構造函數。
是的,這是全部自動創建的設計和所有者屬性指向表單在執行期間以及在崩潰期間。 爲了記錄組件在預期時間似乎被銷燬。 〜TWinControl顯然走過並殺死了所有擁有的組件。有問題的控件的析構函數然後試圖將一個事件傳遞給我們的表單,該表單已經被銷燬,並且當時只剩下一些父類。 – doynax
你爲什麼在析構函數中觸發事件?無論如何,在調用一個事件處理函數之前,你可以簡單地檢查'csDestroying'標誌的'ComponentState'屬性。 –