在 C++ 中创建聚合的代码必须使用聚合字段析构函数吗?

9 c++ aggregate private-members language-lawyer

请考虑以下带有struct B类型字段的聚合的示例U。该字段的析构函数是私有的,但由于friend声明对聚合可用,不能从main函数调用:

class U { 
    ~U() {}
    friend struct B;
};

struct B { U v{}; };

int main()
{
    B b; //ok everywhere
    auto pb = new B; //ok everywhere
    delete pb;
    pb = new B{}; //ok in GCC, error in Clang
    delete pb;
}
Run Code Online (Sandbox Code Playgroud)

如果使用聚合初始化,B{}则代码仅被 GCC 接受,而 Clang 则报告错误:

error: temporary of type 'U' has private destructor
    pb = new B{}; //ok in GCC, error in Clang
               ^
<source>:2:5: note: implicitly declared private here
    ~U() {}
    ^
Run Code Online (Sandbox Code Playgroud)

演示:https : //gcc.godbolt.org/z/c33Gbqfqh

我在https://en.cppreference.com/w/cpp/language/aggregate_initialization 中没有发现任何对“析构函数”的提及。标准是否真的要求聚合字段的析构函数可供聚合的每个潜在用户使用?

bog*_*dan 6

标准确实要求访问析构函数。引用 N4868(最接近已发布的 C++20),[dcl.init.aggr]/8说:

类类型的每个元素的析构函数可能从聚合初始化发生的上下文中调用。[注意:该条款确保在抛出异常的情况下可以为完全构造的子对象调用析构函数。— 尾注 ]

为了完整性,[class.dtor]/15说:

[...] 如果可能调用的析构函数被删除或无法从调用上下文访问,则程序格式错误。


[dcl.init.aggr]/8 由DR2227决议添加,首次发布于 C++20。这是一份缺陷报告,因此编译器也应将其应用于以前的标准版本。