std::forward 的 RValue 引用重载可能导致悬空引用?

RValue-reference overload of std::forward potentially causing dangling reference?

此问题是以下问题的后续问题:

StoryTeller 的回答让我思考了foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get())); 语句中涉及的价值类别。第二次不超载吗

template< class T >
constexpr T&& forward( std::remove_reference_t<T>&& t ) noexcept;

可能会导致悬空引用?将我的链接问题示例更改为

void func(int& lvalue)
{
    std::cout << "I got an lvalue!" << std::endl;
}

void func(int&& rvalue)
{
    std::cout << "I got an rvalue!" << std::endl;
}

// now according to the 2nd overload of std::forward
template <typename T>
T&& myForward(typename std::remove_reference_t<T>&& t)
{
    return static_cast<T&&>(t);
}

struct foo
{
    int i = 42;
    int& get()& { return i; }
    int get()&& { return i; }
};

// now with the inner and the outer forward as in the example on cppreference
template <typename T>
void wrapper(T&& t)
{

    func(myForward<decltype(myForward<T>(t).get())>(myForward<T>(t).get()));
}

int main()
{
    wrapper(foo());

    return 0;
}

让我觉得已经有一个悬空引用涉及:myForward<T>(t).get() returns 一个 int 纯右值,其评估初始化一个临时对象,调用时 typename std::remove_reference_t<T>&& t 绑定到该临时对象myForward<decltype(myForward<T>(t).get())>(myForward<T>(t).get())。 (根据 cppreference,此转换“[...] 产生一个表示临时对象的 xvalue。”但是 xvalue 表达式 究竟是什么 将纯右值绑定到引用?它甚至存在于代码中吗?它不是 myForward<T>(t).get() 因为那是一个纯右值。或者这个纯右值是否通过将它绑定到 [=] 中的引用而转换为亡值20=]?)

接下来,myFoward returns 右值引用 int&&myForward 的这个局部变量,[=25= 的 int&& ]-overload 然后绑定到。最初,我以为这已经引入了悬挂引用,但后来我阅读了 cppreference.com 上的“引用初始化”一文的“临时对象的生命周期”段落。存在“此生命周期规则的例外情况”:

"a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outlives the full expression, it becomes a dangling reference."

总之,myForward 本地的这个临时对象一直存在到完整表达式的分号为止——一切都很好。 但是,我对“如果函数 returns 是一个引用,它比完整表达式还长,它就变成了一个悬空引用”,我的解释是“如果函数 returns 是对该引用参数的引用 ”。那应该意味着改变 wrapper(T&& t) 像这样

template <typename T>
void wrapper(T&& t)
{

    // func(myForward<decltype(myForward<T>(t).get())>(myForward<T>(t).get()));
    int&& ref = std::forward<decltype(std::forward<T>(t).get())>(std::forward<T>(t).get());
    func(ref);
}

应该导致 ref 成为悬空引用。尽管如此,即使在绑定到 int&& ref 和调用 func(ref) 之间将一些其他值放在堆栈上时,我仍然可以在 void func(int&& rvalue) 中打印“42”(正确值)。此外,在 myForward 中打印 twrapper 中的 reffunc 中的 rvalue 的地址始终给出相同的值,这意味着它是同一对象(myForward 本地)。

同时,这应该意味着当使用纯右值调用 std::forward 的第二个重载并且不在同一表达式中使用它返回的引用时,我们正在处理悬空引用。还是我遗漏了有关此主题的内容?

Doesn't the second overload ... potentially cause dangling references?

如果参数是非悬挂引用,则返回的引用也将是非悬挂引用。如果参数是临时的,那么引用将在完整表达式之后变为悬挂。我不会说它是由 std::forward“引起”的。如果您将纯右值传递给 std::forward,那么您可能用错了。

That should mean that changing wrapper(T&& t) like so ... should result in ref being a dangling reference.

正确。 ref 是该版本中的悬空引用。

Still, I can print "42" (the correct value) in void func(int&& rvalue), even when putting some other values on the stack between binding to int&& ref and calling func(ref)

恭喜。您正处于了解未定义行为含义的第一步。