返回临时常量引用的行为与本地常量引用不同?

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

我试图更好地理解如何将左值和右值作为引用处理,所以我创建了这个玩具示例:

#include <iostream>

struct Val
{
    Val(int num) : num(num){};
    ~Val()
    {
        std::cout << "Destructing with value " << num << std::endl;
    }

    int num;
};

const Val &test(const Val &val)
{
    return val;
}
int main()
{
    std::cout<< "Creating foo with value 5" <<std::endl;
    const Val &foo = test(Val(5));
    std::cout<< "Creating bar with value 3" <<std::endl;
    const Val &bar(3);
    std::cout<< "Finishing main function" <<std::endl;
    return 0;
}

打印出:

Creating foo with value 5
Destructing with value 5
Creating bar with value 3
Finishing main function
Destructing with value 3

本质上,我们看到这个右值

Val(5)
绑定到函数
val
中的常量引用参数
test
,并且返回相同的值 - 但是,析构函数会立即被调用,因为它是临时的。但是当我们尝试构造
Val(3)
并分配给 const 引用时,它仍然在整个块的范围内。

我的想法是,我们可以将右值绑定到常量引用,这将延长它们的生命周期,直到该引用超出范围,但这里似乎不一定是这种情况。如果您能深入了解我的误解,我将不胜感激。

c++ reference lifetime temporary temporary-objects
3个回答
5
投票

给定

const Val &foo = test(Val(5));
,临时的
Val(5)
将在完整表达后立即销毁,其生命周期不会延长到参考
foo
的生命周期。它不是直接绑定到
foo
,而是绑定到
test
的参考参数。

参考初始化

(强调我的)

每当引用绑定到临时对象或子对象时 其中,临时的寿命延长以匹配 引用的生命周期,但以下情况除外:

  • 在函数调用中绑定到引用参数的临时绑定存在,直到包含该函数调用的完整表达式结束为止:if 该函数返回一个引用,该引用比完整表达式的寿命长, 它变成了一个悬空的参考。

一般来说,临时的生命周期不能通过以下方式进一步延长: “传递它”:第二个引用,从引用初始化 临时绑定的,不影响其生命周期。


1
投票

当您向 test() 本身添加输出时

const Val &test(const Val &val)
{
    std::cout << "test with value " << val.num << '\n';
    return val;
}

您会看到,临时对象一直存在到函数结束,但不会超出

Creating foo with value 5
test with value 5
Destructing with value 5
Creating bar with value 3
Finishing main function
Destructing with value 3

1
投票

我的想法是,我们可以将右值绑定到常量引用,这将延长它们的生命周期,直到该引用超出范围

是的,确实

val
参数确实延长了Val(5)
的生命周期,但是当
test
返回时,
val
本身就被销毁了,没有任何东西可以让
Val(5)
继续存活,所以它也被销毁了。

通过引用返回,您实际上返回了一个悬空引用,因此您有未定义的行为:

参数val

是对实际参数
Val(5)
的引用这一事实并不影响
val
test
返回后不再可用,并且您正在通过引用返回(好吧,尝试返回)
itval
),而不是其引用的实体。

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