【问题标题】:Is prvalue elision allowed in throw expressionsthrow 表达式中是否允许使用纯右值省略
【发布时间】:2018-08-27 23:55:01
【问题描述】:

§[except.throw] 中,标准规定抛出异常会从 throw 表达式复制初始化异常对象

抛出异常会复制初始化(11.6、15.8)一个临时对象,称为异常对象

那么为什么下面的代码会在 C++17 上编译呢?

class Exception {
public:
   Exception() = default;
   Exception(Exception&&) = delete;
   Exception(const Exception&) = delete;
};

int main() {
    throw Exception{};
    return 0;
}

(https://wandbox.org/permlink/R3WfzfnBAORTLVSy)

复制初始化不包括任何符合prvalue省略的情况(从我看来)。那么为什么上面的代码在 C++17 中编译呢?

【问题讨论】:

  • 您是否对为什么不使用复制构造函数感到困惑?您是否将复制初始化与复制构造混为一谈?

标签: c++ exception exception-handling c++17 prvalue


【解决方案1】:

来自最近的draft standard

11.6 [dcl.init]/15

以大括号或等号初始化器形式发生的初始化 或条件 (9.4),以及在参数传递、函数返回、抛出异常 (18.1)、处理异常 (18.3) 和聚合成员初始化 (11.6.1) 中,称为复制初始化。

所以T x = T(); 是复制初始化的一个例子。抛出异常和许多其他情况也是如此。

复制初始化的作用在 11.6 的其他部分中定义(以及其他形式的初始化)。初始化器中纯右值的相关部分是:

11.6 [dcl.init]/17.6.1

如果初始化表达式是纯右值并且源类型的 cv 非限定版本与目标类是同一类,则使用初始化表达式初始化目标对象

这也称为保证省略。如果初始化表达式是匹配类型的纯右值表达式,则使用纯右值表达式直接构造初始化的目标。

【讨论】:

  • 如何回答这个问题?你是说 T(T(T())) 是复制初始化的一个例子吗?
  • @Curious 从标准草案中提取了两个引用,而不是从提案中提取引用以编辑标准。
  • 对不起。我仍然没有真正遵循。我想这告诉我,我假设复制初始化不是省略的可行候选者可能是错误的。但它在哪里说 throw 表达式是一个可行的省略候选者?
  • @Curious 第一个引号说抛出异常使用复制初始化。第二个表示初始化表达式初始化目标对象。因此Exception{} 初始化对象。我不认为真的有省略,就其本身而言。
  • 啊哈。 [expr] 子句中函数式转换和 static_cast(因此有时是 C 式转换)的详细信息指定如果表达式是用于初始化结果对象的类纯右值,则表达式中的初始化程序或操作数是用于初始化该结果对象,并且这些规则可以递归应用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-19
  • 1970-01-01
  • 2011-04-12
  • 1970-01-01
相关资源
最近更新 更多