当前位置: 首页 > 知识库问答 >
问题:

对指向未内联成员函数的常量指针的调用

仲学真
2023-03-14

现在,我知道没有内联的保证,但是。。。

给定以下内容:

struct Base {
    virtual int f() = 0;
};

struct Derived : public Base {
    virtual int f() final override {
        return 42;
    }
};

extern Base* b;

我们有:

int main() {
    return static_cast<Derived*>(b)->f();
}

编译成:

main:
    movl    $42, %eax
    ret

然而...

int main() {
    return (static_cast<Derived*>(b)->*(&Derived::f))();
}

编译成:

main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    b, %eax
    movl    (%eax), %edx
    movl    %eax, (%esp)
    call    *(%edx)
    leave
    ret

这真的很让人难过。

为什么打给PMF的电话没有被内联?PMF是一个不变的表情!

共有3个答案

艾嘉石
2023-03-14

这确实有点烦人,但这并不奇怪。

大多数编译器转换通过模式匹配工作:识别模式并应用转换。那么,这可能不会被优化的原因是什么呢?好吧,也许只是没有基于此模式编写的转换。

更具体地说,这个问题可能与<代码>有关

徐景明
2023-03-14

内联指针指向函数并不总是可能的(除非编译器能够确定指针实际指向的是什么,这通常很困难,因此编译器可能会在您期望它之前“放弃”)。

编辑

扩展一下我的回答:所有编译器的首要任务是生成正确的代码(尽管有时这也不会发生!).优化,比如内联函数,是编译器只有在“安全”时才会做的事情。编译器可能不太“理解”上面的表达式确实是一个常量表达式,因此退回到“让我们做安全的事情”(即通过虚函数表调用,而不是内联函数)。指向虚拟成员函数的指针在C语言中是一个相当棘手的问题。

谭新知
2023-03-14

这里的问题是,在第一种情况下,基于类型的非虚拟化将间接调用转换为直接调用。添加成员指针时,不能使用基于类型的非虚拟化(因为它通过前端传递到有关调用的类型和虚拟方法的优化信息来工作,在这种情况下,从 中可以不容易知道)。GCC可能能够通过知道B是一个类并且知道其成员只有在构造后才能被调用来不断地将实际访问折叠到虚拟表中。目前它不做这样的分析。

我建议将增强请求填写到GCCbugzilla。

 类似资料:
  • 我遇到了一个语法问题。看另一个StackOverflow答案并不能给出一个适用于我的问题的答案。至少不是我能理解的。 我的计划程序类: 这一切都编译得很好,但问题在于调用该函数中的成员函数指针: 编译这个会给我带来错误; 其他尝试: 有人能帮我解释一下我缺了什么知识吗?

  • 我编写了一个代码来传递函数指针列表(按其名称)作为参数。但我有错误。你能解释为什么我在做地图时有错误吗? 错误: 34:18:错误:无法将'void(Bar::)(int, int)'转换为'std::map, void(*)(int, int) 35:18:错误:无法将“无效(foo::)(整数,整数)”转换为“标准::映射,无效(*)(整数,整型) 41:70:错误:没有用于调用“std::v

  • 一个函数总是占用一段连续的内存区域,函数名在表达式中有时也会被转换为该函数所在内存区域的首地址,这和数组名非常类似。我们可以把函数的这个首地址(或称入口地址)赋予一个 指针变量,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数。这种指针就是 函数指针。 函数指针的定义形式为: returnType (*pointerName)(param list); returnType

  • 假设有一个结构 我得到一个指向该结构的成员的指针,比如作为某个函数的参数: 如何获取指向包含对象的指针?最重要的是:在不违反标准中的某些规则的情况下,也就是说,我想要标准定义的行为,而不是未定义或实现定义的行为。 附带说明:我知道这规避了类型安全。

  • 最近在review代码的时候发现,使用了空指针调用成员函数,并且成员函数内部有使用到成员变量,居然没有出错。很是奇怪,就用一篇博客把关于空指针调用成员函数相关的内容总结起来。 空指针调用成员函数 调用普通成员函数 如果空指针调用普通成员函数,看该函数体中是否使用到了this指针(是否访问非静态成员变量)。如果使用到了this指针,程序会崩溃;如果没有使用到this指针,程序不会崩溃。当然,如果访问

  • FAQs in section [33]: [33.1] “成员函数指针”类型不同于“函数指针”吗? [33.2] 如何将一个成员函数指针传递到信号处理函数,X事件回调函数,系统调用来启动一个线程/任务等? [33.3] 为什么我总是收到编译错误(类型不匹配)当我尝试用一个成员函数作为中断服务例程? when I try to use a member function as an interru