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

问题描述 投票:1回答:3

我知道当我调用实例方法时,对象地址被分配给'this'隐藏指针参数。这样,该方法可以访问当前对象的实例变量,不像静态方法没有此参数,因此无法引用当前实例。

所以我的问题是:

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

  • 实例方法如何引用该对象?
  • 'const this'参数会发生什么?

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

c++ calling-convention
3个回答
1
投票

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

通常在c ++中,可以优化任何不可观察的行为。在没有看到函数定义的情况下,编译器无法知道如何使用this指针,并且必须将对象放在可寻址的内存中。

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


0
投票

实际上temporaries确实有地址并且它们在内存中(除非它们完全被优化),通常在堆栈上就像局部变量一样。 Temporaries在C ++方面是不可寻址的,但在实际生成的代码编译器中可以自由地以任何方式表示它们,包括将它们放在堆栈上,从而使它们可寻址。

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


0
投票

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

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

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

#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;
}

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

© www.soinside.com 2019 - 2024. All rights reserved.