我可以期望此调用内联吗?
Can I expect this call to be inlined?
A * a = new B();
a->foo();
假设 B 派生 A,foo(( 是一个虚函数。这个例子非常频繁,问题是在某些地方据说编译器不会尝试内联它,而在其他地方则恰恰相反。
我个人看不出为什么这个调用不能内联,因为在编译时很容易分辨出哪个函数被调用。
编辑 1:我知道"一般情况",也知道编译器需要许多因素来决定是否内联。如果我问编译器是否可以内联这个特定的调用,这个问题的格式可能会更好。
我问这个问题的原因是这个C++常见问题解答中的一句话,它说:
当通过指针或引用引用对象时,无法内联对虚函数的调用,因为调用必须动态解析。
如果编译器可以以某种方式推断出a
指向的对象是B
的实例(即,如果代码是微不足道的,就像在你的例子中一样(,那么它可以去虚拟化调用 - 尽管它不是必需的。
但关键是,一般来说,调用是在运行时解析的,因为你不知道(编译器也不知道!(a
指向的对象的动态类型是什么。
换句话说,如果编译器不知道*a
的动态类型是什么,因此直到运行时才知道应该调用哪个foo()
函数,则不可能在编译时取消虚拟化调用并内联它。
澄清一下,g++ 显然至少正确地内联了一些微不足道的虚拟调用情况; 这类似于您的情况,只是稍微调整了一下以获得更具可读性的汇编程序:)
void test(int);
class A { public: virtual int Bop() { return 1; } };
class B : public A { virtual int Bop() { return 4711; } };
int main() {
A* a = new B();
test(a->Bop());
}
$ g++ -O99 -S -c test.cpp
$ less test.s
...
main:
.LFB2:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $8, %edi
call _Znwm
movl $4711, %edi // hard coded 4711
movq $_ZTV1B+16, (%rax)
call _Z4testi // calls test()
...
想象一下这样的翻译单元:
计算.cpp:
#include "A.h"
int compute(A * p)
{
return p->get_some_int() * 10;
}
您认为虚拟函数调用如何可能去虚拟化?下面是一个使用示例:
主.cpp:
#include "B.h"
#include "C.h"
int compute(A *);
int main()
{
A * p = rand() % 2 == 0 ? new B : new C;
return compute(x);
}
你不能指望编译器内联它。这取决于编译器和所选的优化级别。假设 B::foo 的实现是可见的,并且在赋值和调用之间没有执行任何操作,那么,是的,目视检查表明编译器有足够的信息可用于进行优化。
但并非必须如此。
在许多其他情况下,它没有足够的信息。
相关文章:
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 函数调用中参数的顺序重要吗
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 从类型std::函数传递变量失败,尽管调用方期望的类型完全相同
- 如何期望通过使用Google Test(Mock)以特定频率调用函数
- 在Google测试框架中,如何期望函数调用或其他功能调用
- 构造函数期望缺少对其他构造函数的调用/候选人期望 1 个参数,提供 0?
- 期望在模拟对象上调用了某个方法.它会破坏封装吗?
- 用指针作为参数函数 - 该函数通过调用期望如何
- 期望使用确切的对象实例作为参数进行调用
- C Google Mock -Expect_Call() - 期望在不直接调用时无法正常工作
- 如何在模拟期望中调用const std::function<>&参数?
- GoogleMock:如何准确地期望一个带有特定参数的调用,并查看故障诊断
- 我可以期望此调用内联吗?
- 使用Google mock,如何在不关心/设置任何调用期望的情况下提供模拟实现
- 期望迭代器在对项调用next()/previous()时具有不同的行为
- 没有匹配的调用函数(期望3个参数,实际0个).第一次在c++中处理向量和字符串
- 如何启动一个std::线程,调用一个期望函数作为参数的函数