以下代码段格式正确吗?
struct A { ~A() = delete; };
A *pa{new A{}};
class B { ~B() = default; };
B *pb{new B{}};
A
乍一看,B
似乎从未使用过的dtor和私有的显式默认dtor (如果有意,则是故意的内存泄漏),这可能暗示它的格式正确。
Clang接受适用于各种编译器和C ++版本(C ++ 11至C ++ 2a)的程序。
另一方面,GCC拒绝该程序使用各种编译器和C ++版本。
struct A { ~A() = delete; }; A *pa{new A{}}; // GCC error: use of deleted function 'A::~A()' class B { ~B() = default; }; B *pb{new B{}}; // GCC error: 'B::~B()' is private within this context
(格式正确的文件;在我提交错误报告之前:针对这种极端情况是否有任何公开的GCC错误报告?我自己搜索过GCC:s bugzilla都没有用。)
特殊的GCC接受用户提供的私有析构函数的情况:
class C { ~C(); };
C *pc{new C{}}; // OK
class D { ~D() {} };
D *pd{new D{}}; // OK
这可能暗示某些GCC对聚合类做了一些特殊的事情,因为A
andB
是聚合,而C
andD
不是。但是,GCC与这种行为不一致,如以下示例所示
struct E {
~E() = delete;
private:
int x;
};
E *pe{new E{}};
这里E
不是集合(私有数据成员),就像集合类A
和B
上面的类一样被拒绝,而的示例F
和G
下面的示例(分别是C ++ 20之前的集合和非集合)
struct F {
F() = default;
~F() = delete;
};
F *pf{new F{}};
struct G {
G() = default;
~G() = delete;
private:
int x;
};
G *pg{new G{}};
都被海湾合作委员会接受。
首先,[class.dtor] / 4明确提到可以删除给定类的所选析构函数:
在类定义的末尾,将在该类中声明的预期析构函数与空参数列表之间执行重载解析,以选择该类的析构函数,也称为selected析构函数。[...]析构函数的选择不构成对所选析构函数的引用或对所选析构函数的奇数用途([basic.def.odr]),特别是所选的析构函数可能会被删除([dcl.fct.def 。删除])。
[class.dtor] / 15决定在哪些情况下隐式调用析构函数;从第一部分开始:
析构函数被隐式调用
- (15.1)对于在程序终止([basic.start.term])时具有静态存储持续时间([basic.stc.static])的构造对象,
- (15.2)对于在线程出口具有线程存储持续时间([basic.stc.thread])的构造对象,
- (15.3)对于在创建对象的块退出([stmt.dcl])时具有自动存储持续时间([basic.stc.auto])的构造对象,
- (15.4)对于构造的临时对象,当其生存期结束时([conv.rval],[class.temporary])。
[...]对于由new表达式([expr.new])分配的构造对象,也可以通过使用delete-expression([expr.delete])隐式调用析构函数;调用的上下文是delete-expression。
(15.1)到(15.4)中的任何一个都不适用于此处,尤其是“对于由new-expression分配的构造对象”(确实适用于此处),析构函数仅通过使用delete-expression隐式调用,我们在此示例中不使用。
[class.dtor] / 15的第二部分介绍了何时可能调用析构函数,以及如果可能会调用并删除析构函数,则程序格式错误:
析构函数也可以显式调用。如果析构函数被调用或在[expr.new],[stmt.return],[dcl.init.aggr],[class.base.init]和[except.throw]中指定,则可能会调用它。如果潜在调用的析构函数被删除或无法从调用上下文访问,则程序格式错误。
在这种情况下,不会显式调用析构函数。
[expr.new](特别是指[expr.new] / 24)在这里不适用,因为它仅与创建类类型的对象数组(使用new-expression)有关。
[stmt.return]在这里不适用,因为它涉及(可能)在return语句中调用构造函数和析构函数。
[dcl.init.aggr](尤其是[dcl.init.aggr] / 8)在这里不适用,因为它涉及聚合元素的潜在调用的析构函数,而不是聚合类本身的潜在调用的析构函数。
[class.base.init]在这里不适用,因为它与(基类)子对象的潜在调用的析构函数有关。
[except.throw](尤其是[except.throw] / 3和[except.throw] / 5)在这里不适用,因为它与异常对象的潜在调用的析构函数有关。
因此,无[class.dtor] / 15适用于这种情况,并且GCC是错误拒绝的例子A
,B
并且E
在OP。正如@JeffGarrett的评论中指出的那样,这看起来像以下打开的GCC错误报告:
而且我们可以注意到,在bug报告指出的,只有GCC错误分配在使用列表初始化,而以下的变形例拒绝这些计划A
,B
并E
全部由GCC接受的:
struct A { ~A() = delete; };
A *pa{new A()};
class B { ~B() = default; };
B *pb{new B()};
struct E {
~E() = delete;
private:
int x;
};
E *pe{new E()};
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句