簡體   English   中英

C ++虛函數:鏈接器是否可以刪除未調用的虛函數表中的條目?

[英]C++ virtual functions: Can the linker remove entries in the virtual function table which aren't called?

這個問題是一種消除未使用的虛函數的后續問題,對我的興趣不夠深入。

問題:在定義具有虛函數的類時,編譯器為虛函數表分配存儲,並存儲指向表中函數的指針。 這會導致鏈接器保留這些函數的代碼,無論它們是否被調用。 即使編譯器優化設置要求消除死代碼,這也可能導致大量死代碼保留在可執行文件中。

現在,如果在可執行文件中沒有任何地方存在特定虛函數的調用(或者換句話說,訪問虛函數表的相應槽),則可以從虛函數表中省略相應的函數指針,並且鏈接器將刪除函數的代碼,可能會進一步遺漏其他未引用的代碼。

顯然,這不能由編譯器完成,因為它只在鏈接時變得清楚是否調用了特定的虛函數(假設靜態鏈接 - 很明顯它不能用動態鏈接完成)。 我對鏈接器不夠熟悉,以便判斷編譯器是否可以以鏈接器可以選擇性地忽略表中各個未使用的條目的方式發出虛函數表。

基本上,我的思路是這樣的:虛函數表中的函數指針是對函數的引用,鏈接器使用該函數來確定函數的代碼需要保留在可執行文件中。 以類似的方式,虛函數調用是對從其虛函數被調用的類派生的所有虛函數表中的特定槽的引用。 這種引用是否可以通過這樣一種方式傳遞給鏈接器:當它沒有引用時,它可以忽略虛函數表槽?

請注意,當編譯器可以在編譯時確定調用目標時,這與使用直接調用替換虛函數調用不同。 我知道一些編譯器可以做到這一點,但這是一個不同的情況,因為函數實際上被調用,並且它是被刪除的虛函數調度的開銷。 在我的情況下,我希望刪除未調用的函數的整個代碼。

如果我可以控制所有類定義,我可以手動刪除所有未調用的虛函數。 但是在使用庫時這是不現實的。

這可以通過“鏈接時間優化”或“整個程序優化”來完成嗎? 是否有成功的編譯器?

死代碼的問題在於,從動態庫的角度來看,編譯器無法確定代碼是否已死。 可執行文件可以動態地包含使用死代碼的庫(從擁有死代碼的類派生)。

除此之外,如果可執行文件是唯一一個進行函數調用的函數,那么在鏈接時更改v表的結構可能會完全正常。 但是,如果動態庫進行任何調用,它將對v表有不同的理解,它將調用錯誤的函數。

由於這些事實,並且在表面上獲得的性能不是很大(如果有的話),優化鏈接器不太可能具有此功能。

虛擬函數的去虛擬化實際上與此相關,並且安全優化鏈接器只能對非常少量的函數調用進行去虛擬化。 例如,如果它可以保證沒有動態庫可以在callstack中扮演任何角色,它只能對函數進行去虛擬化。

編輯 @curiousguy提出了一個案例,編譯器可以通過優化更加自由,也就是說鏈接器可以知道沒有外部代碼知道類。 一個例子是具有文件范圍的類。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM