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
中打印 t
、wrapper
中的 ref
和 func
中的 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)
恭喜。您正处于了解未定义行为含义的第一步。
此问题是以下问题的后续问题:
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
中打印 t
、wrapper
中的 ref
和 func
中的 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)
恭喜。您正处于了解未定义行为含义的第一步。