想象一下,一個項目中,有一個像一個接口類以下內容:vtable爲什麼不能包含重複的函數?
struct Interface
{
virtual void f()=0;
virtual void g()=0;
virtual void h()=0;
};
假設其他地方,有人希望創建一個類實現這個接口,爲此f
,g
,h
都做同樣的事情。
struct S : Interface
{
virtual void f() {}
virtual void g() {f();}
virtual void h() {f();}
};
那麼這將是一個有效的優化,以產生一個虛函數表爲S
其條目都指向S::f
,從而節省的包裝功能g
和h
通話。
打印虛函數表的內容,但表示不執行這種優化:
S s;
void **vtable = *(void***)(&s); /* I'm sorry. */
for (int i = 0; i < 3; i++)
std::cout << vtable[i] << '\n';
0x400940
0x400950
0x400970
與-O3
或-Os
沒有編譯效果,就像在clang和gcc之間切換一樣。
爲什麼這個優化機會錯過了?
目前,這些是我已經考慮(並拒絕)的猜測:
- V表打印代碼實際打印垃圾。
- 性能改進被認爲是毫無價值的。
- ABI禁止它。因爲...
// somewhere-in-another-galaxy.hpp struct X : S { virtual void f(); }; // somewhere-in-another-galaxy.cpp include <iostream> void X::f() { std::cout << "Hi from a galaxy far, far away! "; }
如果編譯器可以實現您的優化這段代碼是行不通的
這個優化對於符合代碼是可見的,因爲指向成員函數的指針會比較相等。 –
這看起來很幼稚,但對我來說,調用'f' *的函數本身不是'f'。所以這很奇怪,如果指向成員函數是平等的,你不覺得嗎? –
@David Schwartz:llvm被認爲能夠完成像通過函數指針的內聯代碼。想必它也可以在'g'和'h'中嵌入'f'的主體呢?這與OP提出的優化不一樣我猜...這個優化在實踐中並不是很重要,所以沒有人在意?感覺就像編譯器檢測到的「指向成員函數的指針」一樣,或者可以修改標準以允許以允許複製ellision的相同方式進行優化 –