5

我正在上一fraction门课作为 CS 作业,并编写了以下代码:

fraction fraction::add(fraction other) {
    fraction temp;

    /* manipulate temp */

    return temp;
}

这非常有效,创建了一个新fraction对象,然后将其返回给调用代码。

问题是,为什么这行得通?当方法返回并因此被销毁时,我的分数temp应该超出范围add,但它会被传回调用代码而没有太多错误。

为什么返回具有本地范围的东西会导致它超出范围后继续存在?

4

2 回答 2

6

您返回的是 的值temp,而不是temp对象本身。该值被复制并返回给调用函数,然后被销毁的事实temp在这里无关紧要。

就像这样:

int a;
{
    int b = 5;
    a = b;
}
std::cout << a << std::endl;

在右大括号之后,b已经超出范围,但a仍然包含 value 5,并且很好。您的函数调用也发生了大致相同的事情。

如果你返回一个指向本地对象的指针,情况就完全不同了。尝试取消引用该指针将调用未定义的行为,因为您正在尝试访问不再存在的对象。但是,当您只使用返回的值时,该对象是否存在并不重要,因为此时您只是拥有它曾经包含的值的自己的副本。(从技术上讲,它仍然是按值返回,在这里,调用函数中的指针将只包含它自己的本地对象所在地址的副本——你不能用它做任何有用的事情,因为曾经驻留在该地址的对象已经结束。)

于 2013-10-22T18:29:01.433 回答
4

它不会继续存在。您按值返回temp被复制(或在 C++11 中移动)到分配给函数的返回值的任何位置,然后temp超出范围并被销毁。

或者,在大多数实现返回值优化temp的现代编译器上,实际上将与您分配函数返回值的对象相同,该对象尚未超出范围。

看一个简单的例子

fraction value;
fraction other_value;
fraction returned = value.add(other_value);

value.add(other_value)被调用时,它temp在成员函数的范围内构造,然后一旦到达 line return temp;temp就会被复制到returned调用者范围内。现在 return 语句已经完成,函数结束,temp超出范围并被销毁。

在 RVO 的情况下,tempandreturned实际上是同一个对象,根本不执行任何复制。

于 2013-10-22T18:29:10.447 回答