gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 10:04:39 25 4
gpt4 key购买 nike

以下代码片段格式正确吗?

struct A { ~A() = delete; };
A *pa{new A{}};

class B { ~B() = default; };
B *pb{new B{}};
乍一看,似乎 A 的已删除 dtor和 B 的私有(private)显式默认 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 接受用户提供的私有(private)析构函数的情况:
class C { ~C(); };
C *pc{new C{}}; // OK

class D { ~D() {} };
D *pd{new D{}}; // OK
这可能暗示某些 GCC 为聚合类做一些特殊的事情,如 AB是聚合,而 CD不是。但是 GCC 与此行为不一致,如下例所示
struct E {
~E() = delete;
private:
int x;
};
E *pe{new E{}};
在哪里 E不是聚合(私有(private)数据成员)同样被拒绝,如聚合类 AB上面,而 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{}};
都被 GCC 接受。

最佳答案

片段格式正确;这是一个 GCC 错误 (59238)
首先,[class.dtor]/4明确提到可以删除给定类的选定析构函数:

At the end of the definition of a class, overload resolution is performed among the prospective destructors declared in that class with an empty argument list to select the destructor for the class, also known as the selected destructor. [...] Destructor selection does not constitute a reference to, or odr-use ([basic.def.odr]) of, the selected destructor, and in particular, the selected destructor may be deleted ([dcl.fct.def.delete]).


[class.dtor]/15控制在哪些情况下隐式调用析构函数;从第一部分开始:

A destructor is invoked implicitly

  • (15.1) for a constructed object with static storage duration ([basic.stc.static]) at program termination ([basic.start.term]),
  • (15.2) for a constructed object with thread storage duration ([basic.stc.thread]) at thread exit,
  • (15.3) for a constructed object with automatic storage duration ([basic.stc.auto]) when the block in which an object is created exits([stmt.dcl]),
  • (15.4) for a constructed temporary object when its lifetime ends ([conv.rval], [class.temporary]).

[...] A destructor may also be invoked implicitly through use of adelete-expression ([expr.delete]) for a constructed object allocated by a new-expression ([expr.new]); the context of theinvocation is the delete-expression.


(15.1) 到 (15.4) 中的任何一个都不适用于此处,尤其是“对于由 new 表达式分配的构造对象”,它确实适用于此处,仅通过使用删除表达式隐式调用析构函数,我们是在这个例子中没有使用。
[class.dtor]/15第二部分涵盖何时可能调用析构函数,以及如果可能调用并删除析构函数,则程序格式错误:

A destructor can also be invoked explicitly. A destructor is potentially invoked if it is invoked or as specified in [expr.new], [stmt.return], [dcl.init.aggr], [class.base.init], and [except.throw].A program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context of the invocation.


在这种情况下,没有显式调用析构函数。
[expr.new] (特别是指 [expr.new]/24 )不适用于此处,因为它仅与创建类类型对象数组时有关(使用新表达式)。
[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 的示例是错误的。 , BE在OP中。正如所指出的 in a comment by @JeffGarrett ,这看起来像以下打开的 GCC 错误报告:
  • Bug 59238 - Dynamic allocating a list-initialized object of a type with private destructor fails.

  • 我们可能会注意到,正如错误报告中指出的那样,GCC 在使用列表初始化分配时只会错误地拒绝这些程序,而以下修改示例 A , BE都被 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()};

    关于c++ - 构造(但不破坏)具有已删除或非用户提供的私有(private)析构函数的类的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65124761/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com