代码之家  ›  专栏  ›  技术社区  ›  Top-Master OMG Ponies

C++规范:重复的方法可以共享相同的指针/地址吗?

  •  1
  • Top-Master OMG Ponies  · 技术社区  · 1 年前

    只是询问C++规范/标准,
    这与Qt无关,但一些Qt知识是被认可的;

    C++规范/标准是否允许两个方法具有相同的指针,我的意思是,如果编译器的优化检测到两个方法是二进制的,是否允许编译器为两个方法发出一次二进制?

    例子:

    class MyClassA {
         inline void maybeOptimize1() {
             // Some code.
         }
    };
    
    class MyClassB : public MyClassA {
         inline void maybeOptimize2() {
             // Imagine exact same code as `maybeOptimize1()` here.
         }
    };
    
    static_assert(&MyClassB::maybeOptimize2 != &MyClassA::maybeOptimize1);
    

    重要性:

    例如,在Qt框架中,我们有 QMetaObject::IndexOfMethod ,如果传递给 static_metacall(...) ,可用于根据方法的指针查找方法/槽的索引。

    1 回复  |  直到 1 年前
        1
  •  3
  •   user17732522    1 年前

    C++标准中没有非静态成员函数的地址概念。不可能获得这样一个函数的地址(在编译代码中的指令/符号地址的意义上)。

    但是,指向成员的指针确实存在,并且 static_assert(&MyClassB::maybeOptimize2 != &MyClassA::maybeOptimize1); 如果两个函数都是非虚拟的并且给定了继承关系,则保证成功。(否则,比较的结果是未指明的,在明显恒定的评估上下文中 static_assert 这意味着该程序将不规范。)看见 [expr.eq]/4 .

    如何实现这一点取决于编译器。例如在 Itanium C++ ABI 对于非虚拟非静态成员函数,函数指针与对象指针调整一起存储,我认为在基类对象偏移为零的情况下,取消重复函数通常不允许区分指针,因此这不是允许的优化。(至少假设该类具有外部链接。否则,我可以看到编译器静态地推理哪些地址被占用。)如果偏移量为非零,那么对象指针调整就可能不同。我需要更详细地考虑这个问题。

    据我所知,MSVC的成员指针实现不符合标准,所以我不知道它在那里会如何表现。

    然而,编译器足够聪明,例如,可以将具有相同主体的函数之一简化为跳转到另一个,以节省重复的指令。这仍然为所发射的函数提供了唯一的符号地址。

    我什么都不能说 QMetaObject::IndexOfMethod ,无论它是依赖于成员指针,还是使用编译器特定的非标准方法,或者它是否依赖于技术上为UB的黑客,因此不在规范范围内(这并不罕见)。