对临时对象的Const引用不会延长其生存期

Const reference to temporary object does not extend its lifetime

本文关键字:生存期 临时对象 Const 引用      更新时间:2023-10-16

我有一个类,从中创建一个临时对象。我可以将const引用绑定到这个临时对象,它可以按预期工作。然而,如果我在这个临时对象上调用一个返回std::move(*this(的成员函数,并绑定到这个返回值,它就不会像我预期的那样工作。下面的简短代码再现了我的问题,并且是不言自明的。

#include <iostream>
#include <cstdlib>
#include <vector>
class myval {
public:
std::vector<int> i;
myval(int i) : i({i}) {}
myval(const myval& v) = delete;
myval(myval&& v) : i(std::move(v.i)) {}
myval&& addone() && {
i[0]++;
return std::move(*this);
}
};
int main()
{
//Object is moved, works like expected
const auto moved_value = myval{7}.addone();
std::cout << moved_value.i[0] << std::endl;
//Const reference is supposed extend the lifetime of a temporary object
const auto& u = myval{7};
//Prints 7, as expected
std::cout << u.i[0] << std::endl;
const auto& v = myval{7}.addone();
//Why does this print 0?
std::cout << v.i[0] << std::endl;
return 0;
}

编辑:

  1. 考虑到对此的解释,是否有可能使此项工作有效,从而使赋值"const auto& v = ...."有效?

  2. 为什么以下作业有效,而我的作业无效?

    const auto& s = std::string("hi")[1];
    std::cout << s;
    

常量引用只会延长函数本地临时库的生存期。在线

const auto& v = myval{7}.addone();

您的引用不绑定到临时引用。addone通过引用返回,这意味着您使用的是左值而不是临时值,因此当完整表达式结束时,您只剩下对不再存在的对象的引用。


关于编辑。制作

const auto& v = myval{7}.addone();

我会将addone更改为像一样按值返回

myval addone() && {
i[0]++;
return std::move(*this);
}

当它将对象移动到临时对象中时,这将为您提供正确的行为,然后您可以延长该对象的生存期。

对于

const auto& s = std::string("hi")[1];
std::cout << s;

你的代码有未定义的行为,不幸的是你得到了你想要的。您正在执行与上一个示例相同的操作,并且您创建的临时字符串没有得到生存期扩展。

引用寿命扩展仅在直接应用于前额临时对象时有效。

应用于引用时没有引用生存期扩展。

myval&& addone() && {
i[0]++;
return std::move(*this);
}

返回一个引用。(右值和左值引用都是引用的类型(

const auto& v = myval{7}.addone();

这不会延长引用的生存期,因为我们将const auto& v绑定到引用,而不是临时的。


我们如何让它发挥作用?重写addone的签名,我们得到:

myval addone() && {
i[0]++;
return std::move(*this);
}

现在它返回一个prvalue而不是引用。

const auto& v = myval{7}.addone();

现在这个引用寿命延长了。

你的"为什么这样有效"后续是因为未定义的行为可以做任何事情,包括"看起来有效"。它不是有效的代码。