【问题标题】:Lifetime extension and the conditional operator寿命延长和条件运算符
【发布时间】:2013-01-02 13:42:57
【问题描述】:

local lvalue references-to-const 和 rvalue references 可以延长临时对象的生命周期:

const std::string& a = std::string("hello");
std::string&& b = std::string("world");

当初始化器不是一个简单的表达式,而是使用条件运算符时,这是否也有效?

std::string&& c = condition ? std::string("hello") : std::string("world");

如果其中一个结果是临时对象,而另一个不是,该怎么办?

std::string d = "hello";
const std::string& e = condition ? d : std::string("world");

当条件为假时,C++ 是否要求延长临时对象的生命周期?

在回答 this question 关于不可复制对象时出现了这个问题。

【问题讨论】:

  • 对于d,混合变体不需要std::move 吗?
  • d 不能绑定到右值引用,它不是右值。
  • 使用 ?: 没问题。在混合情况下,复制 d。由于 ?: 的两边总是以相同的类型结束,编译器知道创建一个对象。
  • @SethCarnegie: d 是一个左值,但表达式(true?d:std::string()) 是一个右值,它引用存储在d 中的值。左值将经过左值到右值的转换(即读取存储在变量中的值)

标签: c++ c++11 rvalue-reference object-lifetime temporary-objects


【解决方案1】:

这两个都很好。

§5.16 说(特别删节):

2 如果第二个或第三个操作数的类型为 void

没有。

3 否则,如果第二个和第三个操作数的类型不同

没有。

4 如果第二个和第三个操作数是相同值类别的glvalues

不。 (在第一个中,两个都是纯右值,在第二个中是一个左值,一个是纯右值。)

5 否则,结果为纯右值

好的,所以这两个结果都是纯右值。所以绑定没问题,但是绑定到什么?

6 左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 标准转换在第二个和第三个操作数上执行。

好的,如果它们还不是右值,那么它们现在都是右值。

6(续)在这些转换之后,应满足以下条件之一:

第二个和第三个操作数的类型相同;结果就是那种类型。如果操作数具有类类型,则结果是结果类型的临时纯右值,根据第一个操作数的值从第二个操作数或第三个操作数复制初始化。

好的,那就是std::string(first_operand)std::string(second_operand)

无论如何,条件表达式的结果是一个新的临时纯右值,它是通过绑定到您的引用而扩展的值。

【讨论】:

  • 当表达式计算为临时值时,GCC 和 clang 都不会复制。这是两者都有的错误吗?
  • @SethCarnegie 我正要问同样的问题with this example code...
  • @FredOverflow 抱歉,clang 确实移动了:liveworkspace.org/code/2bseJY$1 所以这是 GCC 中的错误?
  • 另外,“同值类别的glvalues”到底是什么?如果它们是glvalues,它们就是glvalues,因此它们属于相同的值类别。我错过了什么吗?
  • @Marc:我明白了——Seth 最初关于这个问题的原始问题是针对std::string(正如我的评论所说)。我看到 Fred 的链接示例确实表明 GCC 不尊重复制和移动已被删除。
【解决方案2】:
std::string d = "hello";
const std::string& e = condition ? d : std::string("world");

当条件为假时,C++ 是否要求延长临时对象的生命周期?

会的。条件是一个右值表达式,当与const 引用绑定时,编译器将创建一个未命名的对象并将引用绑定到它。我不能 100% 确定延长寿命的临时对象是 std::string("world") 还是(从概念上)制作(并省略)它的副本。

【讨论】:

  • 嗯,第一种情况似乎适用于具有 deleted 复制构造函数(并且没有移动构造函数)的类型,所以我假设不会有额外的副本在第二种情况下,但我只是猜测。
  • 我认为 4.1p2 适用,因为条件运算符会进行左值到右值的转换:“...如果 glvalue 具有类类型,则转换复制初始化类型为 @987654325 的临时值@来自glvalue,转换的结果是临时的prvalue。”
  • @FredOverflow:如果const T& r = T(); 编译的类型既不能移动也不能复制,则编译器有错误。
  • 我很确定 const T& r = T(); 在 C++98 中总是适用于不可复制的类型。
  • @FredOverflow:在 C++03 12.2p4 中描述了将临时对象复制到对象中并绑定引用的过程。我在 C++11 中没有看到如此明确的描述。 C++03, 12.2p4:在这种情况下,保存表达式结果的临时变量将持续存在,直到对象的初始化完成。该对象是从临时副本中初始化的;
猜你喜欢
  • 1970-01-01
  • 2017-07-15
  • 1970-01-01
  • 1970-01-01
  • 2011-06-07
  • 2016-06-10
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多