繁体   English   中英

“auto&& a= f();”中的 a 的生命周期是多少其中 f() 按值返回 object?

[英]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在这里是什么意思? (linux 盒子上的 GCC)
  2. auto &&应该是转发引用,在这种情况下,由于f()按值返回A object ,因此应该将a推导出为右值引用,对吗?
  3. 如果a确实是右值引用,并且由于(临时)右值的生命周期只能通过 const 左值引用来延长, a go 应该在此行之后从 scope 中取出,对吗?

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

优秀答案的总结,供后人参考:

  1. 1A是类型A的内部表示,由 Guillaume Racicot 编写。 F1AvE表示 Function 样式转换为 typeid(A()) 导致 prvalue,作者 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 给出的链接显示“临时 object 的生命周期可以通过绑定到 const 左值引用或右值引用(自 C++11 起)来扩展......”

1A在这里是什么意思? (linux 盒子上的 GCC)

这意味着名称的长度是1后跟字母。 关于如何修改类型有很多规则,但它会对其命名空间、模板参数值和其他内容进行编码。

auto &&应该是转发引用,在这种情况下,由于 f() 按值返回 A object ,因此应该将 a 推导出为右值引用,对吗?

typeid运算符丢弃所有顶级 cv 和 ref 限定符。

此外,它通过引用查看并返回所引用类型的类型信息。

typeid 运算符页面:

如果 type 是引用类型,则结果引用表示引用类型的 std::type_info object。

但是,是的,推断的类型是A ,所以你声明A&& 但即使a是一个右值引用,表达式a也是一个左值。

如果 a 确实是右值引用,并且由于(临时)右值的生命周期只能通过 const 左值引用来延长,那么 go 应该在此行之后从 scope 中取出,对吗?

根据生命周期延长规则,scope 的生命周期结束。


现在解释为什么 typeid 不同。

这与右值或转发引用无关。 这是最令人头疼的解析问题。 A()是返回A且没有参数的 function。

使用{}进行初始化,您会看到问题消失:

#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的内部名称,“如果type是引用类型,则结果引用代表被引用类型的std::type_info object。 ” - 并且a是引用类型。
    F1AvE表示在typeid(A())中的 Function 样式转换导致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

    显式new_type ( )

    如果new_type命名一个非数组完整的 object 类型,则此表达式是new_type类型的纯右值,指定一个临时的(C++17 前) /其结果 object 是(可能添加了 cv 限定符)(C++17 起)那种类型的。 如果new_type是 object 类型,则 object 是值初始化的。

  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. 它的生命周期不会在完整表达式的末尾结束,而是在封闭块的末尾。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM