繁体   English   中英

变量地址

[英]The variables addresses

看看这段代码:

class Test
{
    //
};

Test TestAddress()
{
    Test test;
    cout << "Object Address in function: " << (int)&test << endl;
    return test;
}

int IntAddress()
{
    int test;
    cout << "Integer Address in function: " <<(int)&test << endl;
    return test;
}

int main() {

    int x = IntAddress();
    cout << "Integer Address in Main: " <<(int)&x << endl;

    Test object = TestAddress();
    cout << "Object Address in Main: " <<(int)&object << endl;

    return 0;
}

输出是:

函数中的整数地址:1076679252
Main中的整数地址:1076679220
功能中的对象地址:1076679221
功能中的对象地址:1076679221

有人可以解释我为什么会这样,当我按值返回一个对象时,我会在函数和main中收到相同的地址。 但是当我用Integer做同样的事情时,这个地方是不同的?

我认为你的编译器正在应用返回值优化 ,其中main()TestAddress()作用于内存中的同一个对象变量

所谓的“自动变量”在堆栈上分配。 分配的时刻可以进行编译器优化。

当按值返回局部变量时,编译器基本上有两个选择:

  • 在函数内分配变量,然后在返回时分配变量
    • 创建一个临时的并复制其中的变量
    • 销毁变量
  • 然后在调用者的=中,将临时文件复制到接收构造变量的调用者中。

或者,它可以:

  • 看到函数局部变量是return语句中使用的唯一表达式(只有一个返回,那里,所以这是微不足道的)
  • 看到返回值实际上用于构造调用者变量,因此......
  • 在调用者空间中只分配一个变量,就在调用之前,函数local本身就是对它的引用,并消除所有的副本。

现在,由于在CPU处理方面“复制整数”和“取消整数”的成本有利于复制(int是CPU原始数字类型),并且因为“临时整数”可以适合CPU寄存器(所以它不是“复制到内存”)编译器使用int的第一种方法。

由于类可以具有任何大小(并且副本可能具有更高的成本),因此编译器可以决定采用第二种方法。

在任何情况下,您都不应该关心:外部可观察行为将是相同的,因为对外部和内部变量的访问是互斥的。

首先,您不需要将指针强制转换为int ,因为operator<<()有一个重载接受void*来打印指针地址。 任何指针都可以传递给<<而不进行转换(除非存在针对该指针类型的专用重载,例如char*指针,在这种情况下,您应该转换为void*而不是int )。

其次,当函数按值返回对象时,大多数编译器都会实现返回值优化 (RVO不用于基本类型,因为副本很便宜)。 所以你的代码在幕后扮演更像这样的角色:

void TestAddress(Test &result)
{
    cout << "Object Address in function: " << &result << endl;
}

int main()
{
    //...

    Test object;
    TestAddress(object);
    cout << "Object Address in Main: " << &object << endl;

    return 0;
}

甚至这个:

void TestAddress(Test &result)
{
    new (&result) Test(); // <-- constructor called here instead!
    cout << "Object Address in function: " << &result << endl;
}

int main()
{
    //...

    Test object; // <-- constructor not called here!
    TestAddress(object);
    cout << "Object Address in Main: " << &object << endl;

    return 0;
}

无论哪种方式,编译器都足够聪明,知道函数内部的临时对象将最终在调用者的对象中,因此它消除了temp并直接作用于调用者的对象。

这就是为什么你看到两个输出语句报告的相同内存地址似乎作用于两个独立的对象 - 它们在使用RVO时实际上是内存中的同一对象。

Wyjun,

按值返回对象时,这两个对象都包含相同的指针。 但是,当您按值返回基元时,函数作用域中的基元将被销毁,其值已经包含在被调用者的堆栈帧中,并且该值将重新分配给新的内存空间。

请让我知道,如果你有任何问题!

感谢您的时间,

暂无
暂无

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

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