使用已删除或非用户提供的私有析构函数构造(但不破坏)类的对象

dfrib

以下代码段格式正确吗?

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对聚合类做了一些特殊的事情,因为AandB是聚合,而CandD不是。但是,GCC与这种行为不一致,如以下示例所示

struct E {
    ~E() = delete; 
private: 
    int x;
};
E *pe{new E{}};

这里E不是集合(私有数据成员),就像集合类AB上面的类一样被拒绝,而的示例FG下面的示例(分别是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{}};

都被海湾合作委员会接受。

dfrib

片段格式正确;这是一个GCC错误(59238

首先,[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是错误拒绝的例子AB并且E在OP。正如@JeffGarrett的评论中指出的那样,这看起来像以下打开的GCC错误报告:

而且我们可以注意到,在bug报告指出的,只有GCC错误分配在使用列表初始化,而以下的变形例拒绝这些计划ABE全部由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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

具有私有构造函数和析构函数的类对象的向量?

为什么不能分配带有已删除或私有析构函数的类的数组?

如何构造具有删除的析构函数的动态对象?

使用私有析构函数删除动态分配的对象

如何允许 std::unique_ptr 访问类的私有析构函数或使用私有析构函数实现 C++ 工厂类?

是否可以实例化具有删除的构造函数和析构函数的非聚合类?

为什么在Singleton类中使用私有析构函数?

析构函数不会破坏对象

为什么此析构函数不必删除类对象?

删除另一个类中带有受保护析构函数的对象

对象的构造函数和析构函数

为类编写复制构造函数会在删除析构函数中的对象时导致意外崩溃

为什么带有用户声明的析构函数的类具有隐式默认构造函数?

为什么在具有用户定义的析构函数的类中获得隐式移动构造函数

私有析构函数,但我可以在VS2015中手动删除对象

为什么在C ++中使用私有副本构造函数与已删除副本构造函数

C ++破坏顺序:在类析构函数之前调用字段析构函数

每次调用私有成员 getter 调用类析构函数

C ++自动生成带有用户声明的析构函数的Move构造函数?

我可以使用指向其析构函数中被破坏对象的指针吗?

C ++如何使用破坏状态的析构函数处理对象的副本?

使用私有构造函数扩展类

带有向量的类构造函数中的析构函数调用

模板类的构造函数和析构函数声明语法

在模板类的构造函数末尾调用的模板的析构函数

类构造函数或析构函数之后的分号(;)

当将对象作为参数传递时,为什么要调用析构函数但不调用构造函数?

有什么方法可以检测是否使用非虚拟基本析构函数正确删除了类?

为什么带有析构函数的类不能简单地移动构造?