话说编译时可确定的virtual函数可以被优化么。。
c++吧
全部回复
仅看楼主
level 12
比如这样的:
ObjectInterface* a = new Object();
a->do_something();
一般的编译器优化能否把do_something在编译时确定?
@怪兽大战魔人 @豌豆夹吧
2014年05月29日 01点05分 1
level 14
这个真不是太清楚
既然是虚函数,应该会丢到运行时来确定吧
虽然具体的例子可能在编译期就能够确定,但我想了下要做到这点有点麻烦,而且也没啥特别的好处,另外也有可能有某些我还没想清楚的风险导致都被丢到运行时了…………
另外,你指的优化是啥?内联?
2014年05月29日 01点05分 2
level 12
@怪兽大战魔人
比如某个stream是这样实现:
struct stream_interface {
virtual char getch() = 0;
};
struct mystream: public stream_interface {
virtual char getch() { ...blabla... };
};
使用的时候:
stream_interface* s = new mystream();
while (bla) {
blabla = s->getch(); // 这里要是还按普通的运行时vtable查地址的话不是慢死了么。。
}
2014年05月29日 01点05分 3
编译时应该都是确定的函数地址
2014年05月29日 01点05分
stream_interface *s = new mystream(); 时,编译器已经计算出基类地址偏移,后面的getch()是确定的。
2014年05月29日 01点05分
这个没办法啊,虽然某种意义上确实有优化的可能,但是做起来很麻烦,还要考虑Linkage之类的。反之即使不优化,也就是偏移+load吧……这个只要cache不miss的话也不会慢太多。总之我似乎没见过这样的优化
2014年05月29日 02点05分
回复 怪兽大战魔人 :看楼下?试了下确实是编译时确定+inline了
2014年05月29日 02点05分
level 15
理论上允许优化成非多态调用,至少C++的语义显然没有禁止。
比如a->do_something();中*a在运行时的动态类型如果能被确定,这个调用就可能被优化成a->A::do_something();这个非多态调用。
但是C++也没有指定虚函数多态调用能在编译时求值的特性(比如virtual和constexpr矛盾),因此实现需要自己分析。
这里如果a没有linkage,优化起来会相对容易,整个过程内推断一遍就行。但是只要有linkage,推断*a的动态类型就得靠过程间优化;如果具有external linkage可能得LTO。相当麻烦。
实际实现有多少我没调查过,不过估计指望不上。麻烦是一个原因;另外就算没优化,这种开销一般也不是很大。
2014年05月29日 01点05分 5
像上面的例子,要是不能编译时确定+inline的话就慢死了。。
2014年05月29日 01点05分
回复 RichSelian :也不会慢到哪去,cache干什么吃的。
2014年05月29日 01点05分
level 15
当然这种优化结合inline以后效果可能是会比较明显。
不过会while里面一个劲调用虚函数然后感觉到瓶颈的C艹用户就没多少……如果会在这里出问题基本上就是用抽了。
最后,要增加优化机会,加final。
2014年05月29日 01点05分 6
level 12
简单验证了下:
struct I {
virtual unsigned X() = 0;
};
struct A: public I {
virtual unsigned X() {
return 12345678;
}
};
int main() {
A a;
I* ia = &a;
return ia->X();
}
用gcc -O -S:
main:
.LFB1:
>>>>.cfi_startproc
>>>>movl>>>>$12345678, %eax
>>>>ret
>>>>.cfi_endproc
[haha][笑眼][OK]
2014年05月29日 02点05分 7
ver?
2014年05月29日 02点05分
手头的4.3没这么干……我总是用老版本……
2014年05月29日 02点05分
回复 怪兽大战魔人 : gcc-4.9.0/clang-3.4.1都可以-O1优化过,gcc-3.4.5 -O3无力。
2014年05月29日 02点05分
回复 RichSelian :[喷]度娘奇葩,什么年头还用gcc3作死。
2014年05月29日 02点05分
level 11
可以被优化,但是不知道有什么编译器这么做了。。
2014年05月29日 02点05分 8
level 14
这个问题细想还是有点意思
如果是同一个unit下的,理论上确实可以优化
不过因为涉及到函数外的数据段,通常局限于过程的优化是不会干这种事的……撑死是优化到最简的偏移+load出来,然后call
没试过ICC,不知道做了很多过程间优化的ICC会怎么样,总觉得也玄的样子
2014年05月29日 02点05分 9
拆开之后gcc -O -flto和clang -O2 -flto还是可以优化的。
2014年05月29日 02点05分
回复 RichSelian :嗯,搜索了下,我发现我的认知落后了……
2014年05月29日 02点05分
level 11
[阴险]
2014年05月29日 02点05分 10
level 15
看来g++的-O2启用的-fdevirtualize和-fdevirtualize-speculatively就会干这个。Clang++也没理由没有。
搜了下发现理论早就有了。
还找到两年前ICPC开IPO的bug,把不该内联的内联了……[狂汗]
2014年05月29日 02点05分 11
2014年05月29日 02点05分
这种长长的单词是怎么找到的。。
2014年05月29日 02点05分
回复 RichSelian :就是拿GCC manual的关于优化的部分顺序遍历瞟一遍……
2014年05月29日 02点05分
level 15
2014年05月29日 02点05分 12
有种把所有函数都virtual掉的冲动。。
2014年05月29日 02点05分
回复 RichSelian :疼牛病得治……
2014年05月29日 02点05分
回复 RichSelian :好吧,其实Java已经就算了。还不如直接拿动态语言艹(defun ...)。
2014年05月29日 02点05分
回复 幻の上帝 :主要是没virtual的话gmock艹得疼。。
2014年05月29日 02点05分
level 14
virtual在确定绑定的时候可以inline吧 两个关键字不冲突
2014年05月29日 02点05分 13
能确定的话inline就顺理成章了。
2014年05月29日 03点05分
level 12
-lto什么的都是坑
modulize才是王道
PS:话说final什么的可以标一标么
2014年05月29日 03点05分 14
只允许一级TU的都是坑。modulize了兼容性也是坑。
2014年05月29日 03点05分
标了final怎么做gmock?
2014年05月29日 04点05分
level 12
2014年05月29日 06点05分 15
level 12
虚个蛋,mcf 一大堆 serializer 都是不虚的,只是包装了个虚的接口类,同时仍然提供非虚的接口。
2014年05月29日 12点05分 17
level 6
我觉得不能,虚函数是一个动态概念,对a的解释只能是以ObjectInterface,真正调用运行的时候需要查询指向对象的虚表,然后才能得到函数入口地址。
2014年05月29日 12点05分 18
1