【问题标题】:Does this code result in a materialized base prvalue, and should it compile?此代码是否会产生物化的基本纯右值,是否应该编译?
【发布时间】:2019-10-23 03:58:57
【问题描述】:

以下代码在 gcc 9.1 godbolt 中编译,但不是 clang 8 godbolt

class A {
protected:
    ~A() = default;
};

class B final : public A {
};

int main() {
    auto b = B{};
}

Clang 的错误:

<source>:10:16: error: temporary of type 'A' has protected destructor
    auto b = B{};
               ^
<source>:3:5: note: declared protected here
    ~A() = default;
    ^

哪个是正确的,为什么?

【问题讨论】:

  • (略)具有相同行为的更简单版本:godbolt.org/z/VUBXqd 基于此,我倾向于认为这是一个错误,因为没有显式默认初始化的相同内容可以编译。 (B b{} 失败,而B b 成功)
  • final 重要吗?编辑:看来不是
  • Clang 应该是正确的。这是由于聚合。试试auto b =B(); 看看它是否可以编译。是stackoverflow.com/questions/56367480/…的副本

标签: c++ language-lawyer c++17 destructor compiler-generated


【解决方案1】:

感谢 cmets 的澄清; 由于 C++17,B{} 是聚合的,即使它是从 A 派生的,因此无权访问 dtor 的用户将为聚合初始化创建一个临时的 A。所以clang拒绝编译是正确的。标准:

no virtual, private, or protected (since C++17) base classes

但是,使用 () 将按照标准所述工作。

基地的dtor 可以是公开的或受保护的。

一个常见的准则是基类的析构函数必须是 公共和虚拟或受保护和非虚拟

see the guideline of standard

与 C++11 相比,表达式 B()prvalueauto b = B(); 是移动构造,移动可能会被忽略,在 C++17 中,没有移动. prvalue 不会被移出。这是值初始化B(),完全等同于:

B();

Value Categories in C++17

Should this code fail to compile in C++17?

【讨论】:

  • 这并没有解决这个问题,这个问题更复杂,涉及到保证复制省略的规则。这与编码风格约定无关。此外,wiki 不是标准。
  • @LightnessRacesinOrbit 该指南确认允许从具有受保护 dtor 的类派生,这就是遗忘(和我)理解 Q 的原因。
  • @curiousguy, @oblivion 我的问题不是通常是否允许从具有受保护析构函数的类派生,而是是否允许这个特定示例,并且编译器不同意。 cmets建议不应该允许它,并且clang拒绝它是正确的。另外,B{} 在这里是聚合初始化,而不是值初始化。
  • 哦,是的。这似乎违反直觉。我可能应该说聚合,但我不确定我没有遗漏什么。 C++ 中的初始化很复杂。 :)
  • cppreference 不是“标准”。
【解决方案2】:

是的,Clang 拒绝代码是正确的。

auto b = B{}; 中,我们有一个聚合初始化,它直接发生在main 函数中。所以这个函数必须能够调用B子类型的析构函数,以防在初始化过程中出现异常。

引自 N4861(最后的 C++20 草案)[dcl.init.aggr]/8:

类类型的每个元素的析构函数都可能被调用 从聚合初始化发生的上下文中。 [ 笔记: 此规定确保可以调用析构函数 完全构造的子对象,以防引发异常。 - 结尾 注意]

为了完整,引用[class.dtor]/15

[...] 如果一个潜在的析构函数 调用被删除或无法从上下文中访问 调用。

【讨论】:

  • N4868 更接近于 C++20,部分原因是子句重组。
  • 我认为问题在 C++17 和 C++20 中是一样的。至少编译器在两种模式下都会发出相同的错误。但在 C++20 中,该标准更好地阐明了这种行为。
  • 当然——我并没有声称有什么不同,只是想让人们使用最好的“C++20”作为参考。
猜你喜欢
  • 2019-10-15
  • 1970-01-01
  • 2019-03-24
  • 2015-06-24
  • 1970-01-01
  • 2017-04-29
  • 2012-01-03
  • 2022-11-22
  • 1970-01-01
相关资源
最近更新 更多