gpt4 book ai didi

c++ - 以非多态方式调用虚函数的成本是多少?

转载 作者:可可西里 更新时间:2023-11-01 17:37:10 25 4
gpt4 key购买 nike

我有一个纯抽象基类和两个派生类:

struct B { virtual void foo() = 0; };
struct D1 : B { void foo() override { cout << "D1::foo()" << endl; } };
struct D2 : B { void foo() override { cout << "D1::foo()" << endl; } };

在 A 点调用 foo 与调用非虚拟成员函数的成本相同吗?或者它是否比 D1 和 D2 不是从 B 派生的更昂贵?

int main() {
D1 d1; D2 d2;
std::vector<B*> v = { &d1, &d2 };

d1.foo(); d2.foo(); // Point A (polymorphism not necessary)
for(auto&& i : v) i->foo(); // Polymorphism necessary.

return 0;
}

答案: Andy Prowl 的答案是正确的答案,我只是想添加 gcc 的汇编输出(在 godbolt 中测试:gcc- 4.7 -O2 -march=native -std=c++11)。直接函数调用的成本是:

mov rdi, rsp
call D1::foo()
mov rdi, rbp
call D2::foo()

对于多态调用:

mov rdi, QWORD PTR [rbx]
mov rax, QWORD PTR [rdi]
call [QWORD PTR [rax]]
mov rdi, QWORD PTR [rbx+8]
mov rax, QWORD PTR [rdi]
call [QWORD PTR [rax]]

但是,如果对象不是从 B 派生的,而您只是执行直接调用,gcc 将内联函数调用:

mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:std::cout
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)

如果 D1D2 不是从 B 派生的,这可以实现进一步的优化所以我猜不,它们不等价(至少对于具有这些优化的 gcc 版本,-O3 产生了类似的输出而没有内联)。在 D1D2 确实派生自 B 的情况下,是否存在阻止编译器内联的内容?

“修复”:使用委托(delegate)(也就是自己重新实现虚函数):

struct DG { // Delegate
std::function<void(void)> foo;
template<class C> DG(C&& c) { foo = [&](void){c.foo();}; }
};

然后创建一个委托(delegate) vector :

std::vector<DG> v = { d1, d2 };

如果您以非多态方式访问方法,则允许内联。但是,我猜访问 vector 会比仅使用虚函数(还不能用 godbolt 测试)慢(或者至少一样快,因为 std::function 使用虚函数进行类型删除)。

最佳答案

Does calling foo in Point A cost the same as a call to a non-virtual member function?

是的。

Or is it more expensive than if D1 and D2 wouldn't have derived from B?

没有。

编译器将静态解析这些函数调用,因为它们不是通过指针或引用执行的。由于调用该函数的对象的类型在编译时是已知的,因此编译器知道必须调用 foo() 的哪个实现。

关于c++ - 以非多态方式调用虚函数的成本是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14922890/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com