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

问题是,

  1. 这里的1A是什么意思? (GCC 在 linux 框上)
  2. auto && 应该是一个转发引用,在这种情况下,由于 f() returns 一个 A 对象的值,a 应该被推断为右值引用,正确吗?
  3. 如果 a 确实是右值引用,并且由于(临时)右值的生命周期只能通过 const 左值引用来延长,a 应该在这一行之后立即超出范围,是对吗?

编辑:修复了最后一个 cout 语句中最令人烦恼的问题,正如许多人指出的那样。

总结 伟大的答案,供后代参考:

  1. 1A 是类型 A 的内部表示,作者是 Guillaume Racicot。 F1AvE 表示在 typeid(A()) 中转换为纯右值的函数样式,由 Ted Lyngmo 提供。
  2. 原来 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
  1. Richard Critten 给出了 link 表示 "The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference (since C++11)..."

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;
}
  1. lAA 的内部名称,“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.

  2. 是的,如下所示:

    static_assert(std::is_rvalue_reference_v<decltype(a)>); // like this, ...
    static_assert(std::is_same_v<decltype(a), A&&>);        // or like this
    
  3. 它的生命周期不会在完整表达式的末尾结束,而是在封闭块的末尾结束。