a in "auto&& a= f();" where f() returns 一个对象的生命周期是多少?
What is the life time of a in "auto&& a= f();" where f() returns an object by value?
#include <iostream>
#include <typeinfo>
class A {};
A f() { return A(); }
int main() {
auto &&a = f();
std::cout << typeid(f()).name() << std::endl;
std::cout << typeid(a).name() << std::endl;
std::cout << typeid(A{}).name() << std::endl;
return 0;
}
输出
1A
1A
1A
问题是,
- 这里的
1A
是什么意思? (GCC 在 linux 框上)
auto &&
应该是一个转发引用,在这种情况下,由于 f()
returns 一个 A
对象的值,a
应该被推断为右值引用,正确吗?
- 如果
a
确实是右值引用,并且由于(临时)右值的生命周期只能通过 const 左值引用来延长,a
应该在这一行之后立即超出范围,是对吗?
编辑:修复了最后一个 cout
语句中最令人烦恼的问题,正如许多人指出的那样。
总结 伟大的答案,供后代参考:
1A
是类型 A
的内部表示,作者是 Guillaume Racicot。 F1AvE
表示在 typeid(A()) 中转换为纯右值的函数样式,由 Ted Lyngmo 提供。
- 原来
typeid()
不是检查引用的工具,因为它给出了引用的结束类型。 Ted Lyngmo 给出了正确的方法,是的,它是一个 r 值参考。
static_assert(std::is_rvalue_reference_v<decltype(a)>); // like this, ...
static_assert(std::is_same_v<decltype(a), A&&>); // or like this
what does 1A
mean here? (GCC on a linux box)
表示名字的长度是1
后面跟着字母。关于如何破坏类型有很多规则,但它编码了它的命名空间、模板参数值和其他东西。
auto &&
should be a forwarding reference, and in this case since f() returns an A object by value, a should be deduced to rvalue reference, correct?
typeid
运算符丢弃所有顶级 cv 和 ref 限定符。
此外,它会查看引用并 returns 所引用类型的类型信息。
来自 typeid operator 页面:
If type is a reference type, the result refers to a std::type_info object representing the referenced type.
但是,是的,推导的类型是 A
,因此您要声明 A&&
。但即使 a
是右值引用,表达式 a
也是左值。
If a is indeed rvalue reference, and since a (temporary) rvalue's lifetime could only be extended by a const lvalue ref, a should go out of scope right after this line, is that correct?
根据生命周期延长规则,生命周期在范围结束时结束。
现在了解为什么 typeid 不同。
这与右值或转发引用无关。这是最令人头疼的解析问题。 A()
是 returns A
并且没有参数的函数。
使用{}
进行初始化,您会发现问题消失了:
#include <iostream>
#include <typeinfo>
class A {};
A f() { return A(); }
int main() {
auto &&a = f();
std::cout << typeid(f()).name() << std::endl; // 1A
std::cout << typeid(a).name() << std::endl; // 1A
std::cout << typeid(A{}).name() << std::endl; // 1A
return 0;
}
lA
是 A
的内部名称,“If 类型 是引用类型,结果引用表示引用类型的 std::type_info
对象。" - a
是引用类型。
F1AvE
表示在 typeid(A())
中转换为 prvalue 的函数样式。您可以与更熟悉的内容进行比较,例如 int()
,其中 typeid::name()
从 lA
:
更改为 i
std::cout << typeid(int()).name() << std::endl; // FivE
std::cout << typeid(A()).name() << std::endl; // F1AvE
std::cout << typeid(int{}).name() << std::endl; // i
std::cout << typeid(A{}).name() << std::endl; // 1A
Explicit cast new_type ( )
:
If new_type names a non-array complete object type, this expression is an prvalue of type new_type, designating a temporary (until C++17) / whose result object is (possibly with added cv-qualifiers) (since C++17) of that type. If new_type is an object type, the object is value-initialized.
是的,如下所示:
static_assert(std::is_rvalue_reference_v<decltype(a)>); // like this, ...
static_assert(std::is_same_v<decltype(a), A&&>); // or like this
它的生命周期不会在完整表达式的末尾结束,而是在封闭块的末尾结束。
#include <iostream>
#include <typeinfo>
class A {};
A f() { return A(); }
int main() {
auto &&a = f();
std::cout << typeid(f()).name() << std::endl;
std::cout << typeid(a).name() << std::endl;
std::cout << typeid(A{}).name() << std::endl;
return 0;
}
输出
1A
1A
1A
问题是,
- 这里的
1A
是什么意思? (GCC 在 linux 框上) auto &&
应该是一个转发引用,在这种情况下,由于f()
returns 一个A
对象的值,a
应该被推断为右值引用,正确吗?- 如果
a
确实是右值引用,并且由于(临时)右值的生命周期只能通过 const 左值引用来延长,a
应该在这一行之后立即超出范围,是对吗?
编辑:修复了最后一个 cout
语句中最令人烦恼的问题,正如许多人指出的那样。
总结 伟大的答案,供后代参考:
1A
是类型A
的内部表示,作者是 Guillaume Racicot。F1AvE
表示在 typeid(A()) 中转换为纯右值的函数样式,由 Ted Lyngmo 提供。- 原来
typeid()
不是检查引用的工具,因为它给出了引用的结束类型。 Ted Lyngmo 给出了正确的方法,是的,它是一个 r 值参考。
static_assert(std::is_rvalue_reference_v<decltype(a)>); // like this, ...
static_assert(std::is_same_v<decltype(a), A&&>); // or like this
what does
1A
mean here? (GCC on a linux box)
表示名字的长度是1
后面跟着字母。关于如何破坏类型有很多规则,但它编码了它的命名空间、模板参数值和其他东西。
auto &&
should be a forwarding reference, and in this case since f() returns an A object by value, a should be deduced to rvalue reference, correct?
typeid
运算符丢弃所有顶级 cv 和 ref 限定符。
此外,它会查看引用并 returns 所引用类型的类型信息。
来自 typeid operator 页面:
If type is a reference type, the result refers to a std::type_info object representing the referenced type.
但是,是的,推导的类型是 A
,因此您要声明 A&&
。但即使 a
是右值引用,表达式 a
也是左值。
If a is indeed rvalue reference, and since a (temporary) rvalue's lifetime could only be extended by a const lvalue ref, a should go out of scope right after this line, is that correct?
根据生命周期延长规则,生命周期在范围结束时结束。
现在了解为什么 typeid 不同。
这与右值或转发引用无关。这是最令人头疼的解析问题。 A()
是 returns A
并且没有参数的函数。
使用{}
进行初始化,您会发现问题消失了:
#include <iostream>
#include <typeinfo>
class A {};
A f() { return A(); }
int main() {
auto &&a = f();
std::cout << typeid(f()).name() << std::endl; // 1A
std::cout << typeid(a).name() << std::endl; // 1A
std::cout << typeid(A{}).name() << std::endl; // 1A
return 0;
}
更改为lA
是A
的内部名称,“If 类型 是引用类型,结果引用表示引用类型的std::type_info
对象。" -a
是引用类型。
F1AvE
表示在typeid(A())
中转换为 prvalue 的函数样式。您可以与更熟悉的内容进行比较,例如int()
,其中typeid::name()
从lA
:i
std::cout << typeid(int()).name() << std::endl; // FivE std::cout << typeid(A()).name() << std::endl; // F1AvE std::cout << typeid(int{}).name() << std::endl; // i std::cout << typeid(A{}).name() << std::endl; // 1A
Explicit cast
new_type ( )
:If new_type names a non-array complete object type, this expression is an prvalue of type new_type, designating a temporary (until C++17) / whose result object is (possibly with added cv-qualifiers) (since C++17) of that type. If new_type is an object type, the object is value-initialized.
是的,如下所示:
static_assert(std::is_rvalue_reference_v<decltype(a)>); // like this, ... static_assert(std::is_same_v<decltype(a), A&&>); // or like this
它的生命周期不会在完整表达式的末尾结束,而是在封闭块的末尾结束。