当它被绑定到调用函数中的const引用时,它的返回值的生命周期如何扩展到调用函数的范围?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当它被绑定到调用函数中的const引用时,它的返回值的生命周期如何扩展到调用函数的范围?相关的知识,希望对你有一定的参考价值。

“如果从函数返回一个值(不是引用),那么将它绑定到调用函数中的const引用,它的生命周期将扩展到调用函数的范围。”

所以:案例A.

const BoundingBox Player::GetBoundingBox(void)
{
    return BoundingBox( &GetBoundingSphere() );
}

从函数const BoundingBox返回GetBoundingBox()类型的值

变体I :(将它绑定到const引用)

const BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();

变体II :(将它绑定到const副本)

const BoundingBox l_Bbox = l_pPlayer->GetBoundingBox();

两者都工作正常,我没有看到l_Bbox对象超出范围。 (虽然,我在变体1中理解,复制构造函数未被调用,因此稍微好于变体II)。

另外,为了比较,我做了以下更改。

案例B

BoundingBox Player::GetBoundingBox(void)
{
    return BoundingBox( &GetBoundingSphere() );
}

与变体:我

BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();

和II:

BoundingBox l_Bbox = l_pPlayer->GetBoundingBox();

对象l_Bbox仍然没有超出范围。如何“将它绑定到调用函数中的const引用,它的生命周期将扩展到调用函数的范围”,真正将对象的生命周期延长到调用函数的范围?

我在这里错过了一些小事吗?

答案

通常,临时对象(例如函数调用返回的对象)的生命周期延伸到“封闭表达式”的末尾。但是,对引用的临时绑定通常会将其生命周期“提升”到引用的生命周期(可能是也可能不是调用函数的生命周期),但有一些例外情况。这包含在12.2 / 5“临时对象”中的标准中:

除了下面指定的内容之外,引用绑定的临时对象或作为临时绑定对象的子对象的完整对象的临时对象的生命周期仍然存在。绑定到构造函数的ctor-initializer(12.6.2)中的引用成员的临时绑定将持续存在,直到构造函数退出。在函数调用(5.2.2)中与引用参数的临时绑定将持续存在,直到包含该调用的完整表达式完成为止。

有关更多信息,请参阅以下内容

一个可能有助于可视化正在发生的事情的示例:

#include <iostream>
#include <string>

class foo {
public:
    foo( std::string const& n) : name(n) { 
        std::cout << "foo ctor - " << name + " created
"; 
    };
    foo( foo const& other) : name( other.name + " copy") { 
        std::cout << "foo copy ctor - " << name + " created
";
    };

    ~foo() { 
        std::cout << name + " destroyed
"; 
    };

    std::string getname() const { return name; };
    foo getcopy() const { return foo( *this); };

private:
    std::string name;
};

std::ostream& operator<<( std::ostream& strm, foo const& f) {
    strm << f.getname();
    return strm;
}


int main()
{
    foo x( "x");

    std::cout << x.getcopy() << std::endl;

    std::cout << "note that the temp has already been destroyed


";

    foo const& ref( x.getcopy());

    std::cout << ref << std::endl;

    std::cout << "the temp won't be deleted until after this...

";
    std::cout << "note that the temp has *not* been destroyed yet...

";
}

哪个显示:

foo ctor - x created
foo copy ctor - x copy created
x copy
x copy destroyed
note that the temp has already been destroyed


foo copy ctor - x copy created
x copy
the temp won't be deleted until after this...

note that the temp has *not* been destroyed yet...

x copy destroyed
x destroyed
另一答案

首先,临时对象的生命周期被扩展到绑定到它的const引用的生命周期,而不是“到调用函数的范围”(尽管可能是那个奇怪的措辞“调用函数的范围”) 。这就是你的CASE A所说明的,你将const引用附加到临时。只要参考存在,临时就会继续存在。当引用结束其生命周期时,临时对象也会被销毁。

其次,你的CASE B只是形成不良,不可编辑。即,

BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox(); 

是非法的。在C ++中附加非const引用到临时是非法的。如果您的编译器允许它,它必须是编译器的怪癖/扩展,这与C ++语言几乎没有关系。

另一答案

关键是当按值返回时,该值将复制到您为该函数分配结果的变量中。 (就像你说的那样 - 复制构造函数被调用)。没有终身延伸,你只需创建一个全新的对象。

通过引用返回时,您只需将指针传递给函数中定义的变量。因此,不会创建新对象,只需在函数外部引用它即可。在这种情况下,函数内部变量的生命周期被扩展。

另一答案

通常,如果从函数返回值的对象,则在赋值表达式完成时将销毁所述对象:

myclass X = getX(); // after copy constructor, the returned value is destroyed
                    // (but you still hold a copy in X)

在您描述的情况下,稍后将销毁返回的值,允许您使用它:

const myclass& X = getX();
cout << X.a << endl; // still can access the returned value, it's not destroyed

以上是关于当它被绑定到调用函数中的const引用时,它的返回值的生命周期如何扩展到调用函数的范围?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能将 const 左值引用绑定到返回 T&& 的函数?

为啥在特殊成员函数中将 r 值绑定到 const 左值引用是非法的?

返回 const 引用和 rvalue 引用之间的区别

Java Script函数变量对象

JavaScript函数认识,Js中的常见函数

javascript中的this绑定