将 const 引用返回到临时行为与本地 const 引用不同?
Returning const reference to temporary behaves differently than local const reference?
我试图更好地了解如何将左值和右值作为引用处理,因此我创建了这个玩具示例:
#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)
绑定到函数 test
中的 const 引用参数 val
,并且返回相同的值 — 然而,析构函数会立即被调用一个临时的。但是当我们尝试构造 Val(3)
并分配给一个 const 引用时,它仍然在整个块的范围内。
我的想法是我们可以将右值绑定到 const 引用,这将延长它们的生命周期,直到该引用超出范围,但这里似乎不一定是这种情况。如果您能深入了解我的误解,我将不胜感激。
给定 const Val &foo = test(Val(5));
,临时 Val(5)
将在完整表达式后立即销毁,其生命周期不会延长至引用 foo
的生命周期。不是直接绑定到foo
,而是绑定到test
.
的引用参数
(强调我的)
Whenever a reference is bound to a temporary or to a subobject
thereof, the lifetime of the temporary is extended to match the
lifetime of the reference, with the following exceptions:
- 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.
In general, the lifetime of a temporary cannot be further extended by
"passing it on": a second reference, initialized from the reference to
which the temporary was bound, does not affect its lifetime.
I was under the conception that we can bind rvalues to const references and that'll extend their lifetime until that reference goes out of scope
是的,确实 val
参数 确实 延长了 Val(5)
的生命周期,但是当 test
return 时,val
本身被摧毁了,没有什么能让 Val(5)
活着,所以它也被摧毁了。
并且通过 return 引用你实际上是 return 悬空引用,所以你有未定义的行为:事实上 参数 val
是对实际参数的引用 Val(5)
不影响 val
在 test
return 之后不再可用的事实,而你是 returning(好吧,试图 return)它 (val
) 通过引用,而不是它引用的实体。
当您将输出添加到 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
我试图更好地了解如何将左值和右值作为引用处理,因此我创建了这个玩具示例:
#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)
绑定到函数 test
中的 const 引用参数 val
,并且返回相同的值 — 然而,析构函数会立即被调用一个临时的。但是当我们尝试构造 Val(3)
并分配给一个 const 引用时,它仍然在整个块的范围内。
我的想法是我们可以将右值绑定到 const 引用,这将延长它们的生命周期,直到该引用超出范围,但这里似乎不一定是这种情况。如果您能深入了解我的误解,我将不胜感激。
给定 const Val &foo = test(Val(5));
,临时 Val(5)
将在完整表达式后立即销毁,其生命周期不会延长至引用 foo
的生命周期。不是直接绑定到foo
,而是绑定到test
.
(强调我的)
Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference, with the following exceptions:
- 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.
In general, the lifetime of a temporary cannot be further extended by "passing it on": a second reference, initialized from the reference to which the temporary was bound, does not affect its lifetime.
I was under the conception that we can bind rvalues to const references and that'll extend their lifetime until that reference goes out of scope
是的,确实 val
参数 确实 延长了 Val(5)
的生命周期,但是当 test
return 时,val
本身被摧毁了,没有什么能让 Val(5)
活着,所以它也被摧毁了。
并且通过 return 引用你实际上是 return 悬空引用,所以你有未定义的行为:事实上 参数 val
是对实际参数的引用 Val(5)
不影响 val
在 test
return 之后不再可用的事实,而你是 returning(好吧,试图 return)它 (val
) 通过引用,而不是它引用的实体。
当您将输出添加到 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