繁体   English   中英

CPU 寄存器中返回的用户定义类型的 C++ 对象。 实例方法如何工作?

[英]C++ Object of User-Defined Type Returned in CPU Register. How Do Instance Methods Work?

我知道当我调用一个实例方法时,对象地址被分配给“这个”隐藏指针参数。 这样方法就可以访问当前对象的实例变量,不像静态方法没有这个参数,所以不能引用当前实例。

所以我的问题是:

当一个小对象在 CPU 寄存器中返回时(通常在 RAX 寄存器中),由于该对象没有地址,因为它不在内存中,

  • 实例方法如何引用对象?

  • 'const this' 参数会发生什么?

在这种情况下没有可用的地址。

假设编译器无法优化方法调用,它将被迫将对象放入内存并将地址传递给该内存给函数。

通常在 C++ 中,任何不可观察的行为都可以被优化掉。 如果没有看到函数定义,编译器就无法知道this指针是如何使用的,必须将对象放在可寻址内存中。

请参阅此示例https://gcc.godbolt.org/z/Zff5nr ,其中对象在eax寄存器中返回,存储在堆栈中,其地址在rdi寄存器中传递给成员函数。

其实临时工确实有地址,他们在存储器中(除非他们完全优化掉),通常在堆栈就像局部变量。 临时文件在 C++ 中是不可寻址的,但在实际生成的代码中,编译器可以以任何它想要的方式自由地表示它们,包括将它们放在堆栈上,从而使它们可寻址。

在将语言结构与实际生成的代码进行比较时,您不应该从字面上考虑语言结构。 例如,如果您调用的方法实际上是由编译器内联的,则this指针甚至可能根本不作为指针存在。 至于const thisconst this是一个纯粹的编译时概念,它只帮助编译器决定它可以执行哪些优化,但是,它绝不是在运行时强制执行的。

这是编译器的问题,而不是程序员的问题。 该语言要求this指针在实例方法中可用。 如果优化编译器决定它可以满足要求并且仍然将所有内容保留在寄存器中,则可以根据 if规则这样做:只要可观察的行为与机器严格遵循的行为相同,则实现的内部结构无关紧要标准(没有优化)会产生。

因此,除非您针对具有特定编译选项的特定编译器,否则无法回答此问题。

例如,让我们看下面的代码:

#include <iostream>
#include <iomanip>

class Foo {
    int val;

public:
    Foo(int val = 0): val(val) {}

    friend std::ostream& operator << (std::ostream& out, const Foo& f);
};

std::ostream& operator << (std::ostream& out, const Foo& f) {
    out << std::hex << std::setw(2) << f.val;
    return out;
}

int main() {
    for (int i=0; i<10; i++) {
        std::cout << Foo(i);
    }
    std::cout << std::endl;
    return 0;
}

编译器可以很容易地得出结论,这是一个单一的编译单元程序:它包含main并且不使用标准库之外的外部引用。 它只是恢复到:

#include <iostream>
#include <iomanip>

int main() {
    for (int i=0; i<10; i++) {
        std::cout << std::hex << std::setw(2) << i;
    }
    std::cout << std::endl;
    return 0;
}

优化整个类定义和友元operator <<

一个非常聪明的计算机甚至可以猜测,因为10是一个常量 expr,所以一切都可以在编译时解析,并且可以生成与以下相同的代码:

#include <iostream>

int main() {
    std::cout << " 0 1 2 3 4 5 6 7 8 9\n";
    return 0;
}

我必须承认,我不会对第一个优化感到惊讶,但我知道没有真正的编译器会生成第二个优化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM