【问题标题】:Is destroying form of operator delete required to actually destroy the object?实际销毁对象是否需要销毁运算符 delete 形式?
【发布时间】:2021-06-05 06:32:16
【问题描述】:

C++20 增加了 operator delete 的破坏形式,由 std::destroying_delete_t 参数区分。它会导致 delete 表达式在调用 operator delete 之前不再销毁对象。

目的是在显式调用对象的析构函数和释放内存之前,允许以依赖于对象状态的方式自定义删除。

但是,我不清楚在实现这样的运算符时,我是否真的需要销毁对象。具体来说,我是否允许拥有一个静态对象池,并将它们分配给用户,这些用户随后可以将它们视为动态分配的?这样在对象上执行的delete 表达式只会将其返回到池中而不会破坏它。例如,以下程序是否定义明确?

#include <new>
 
struct A {
    virtual ~A() = default;
};

// 'Regular' dynamically allocated objects
struct B : A {
    static A* create() {
        return new B();
    }

private:
    B() = default;
};

// Pooled, statically allocated objects
struct C : A {
    static A* create() {
        for (auto& c: pool) {
            if (!c.in_use) {
                c.in_use = true;
                return &c;
            }
        }
        throw std::bad_alloc();
    }

private:
    static C pool[3];

    bool in_use = false;

    C() = default;

    void operator delete(C *c, std::destroying_delete_t) {
        c->in_use = false;
    }
};

C C::pool[3];

// Delete them identically via the common interface.
void do_something_and_delete(A* a) {
    delete a;
}

int main() {
    do_something_and_delete(B::create());
    do_something_and_delete(B::create());
    do_something_and_delete(C::create());
    do_something_and_delete(C::create());
}

【问题讨论】:

    标签: c++ language-lawyer c++20 delete-operator


    【解决方案1】:

    销毁删除操作符(定义为by its proposal)的目的是有效地处理创建和销毁对象的能力,这些对象的释放和销毁出于某种原因需要访问该对象。它通过防止在使用破坏运算符删除功能的对象上调用 delete 时自动调用对象的析构函数来实现这一点。然后将(仍然存在的)对象传递给销毁运算符 delete,以便它可以执行释放和销毁业务。

    它的目的是不是声明delete whatever;对用户撒谎关于这个声明完成了什么。但是由于该功能的一个用例(没有virtual 函数的虚拟析构函数),该功能可以(ab)用来欺骗用户。

    对象的生命周期在其析构函数被输入时(或存储被重用/释放时)结束。如果(ab)使用销毁运算符 delete 来阻止调用该析构函数,则 deleteing 对象不会结束其生命周期。

    但是对用户撒谎是个坏主意,你不应该这样做。

    【讨论】:

    • 而覆盖常规的virtual 函数不是以完全相同的方式“撒谎”吗?用户不应该关心对象是否“真的”被破坏。从他们的角度来看,在任何一种情况下,都不允许在 delete whatever; 之后取消引用 whatever。这只是抽象。
    • @yurikilochek:“重写常规虚函数不是以完全相同的方式“撒谎”吗?”不。通过声明一个函数 virtual,您是在声明意图被覆盖。通过覆盖它,您说明了替换基类版本的意图。在所有情况下,所有相关方的意图都很明确。当你让delete whatever; 没有真正摧毁whatever 时,没有任何背信弃义。
    • @yurikilochek:“这只是抽象。”这是一个糟糕的抽象,它扭曲了显而易见的代码的含义,使其并非如此。如果您想要一个接口,您可以在其中使用一个对象一段时间,然后将其返回以供以后使用,那么请创建该接口。不要仅仅因为技术上可行就将delete 改造成该机制。如果您想对此类类型使用智能指针,您可以提供删除器来调用您的返回 API,而不是覆盖基本句法结构的行为,例如 delete
    • 这个问题被标记为语言律师。如果OP应该,答案会花费大量时间进行道德化,而没有时间引用标准。这似乎不适合这样一个标记的问题?它确实对它是否合法说“是”,基于声称删除对象的结束生命周期是调用析构函数的(唯一)函数,所以我猜是这样吗?
    • @Yakk-AdamNevraumont:“没有时间引用标准”这是允许的,因为标准中没有任何内容禁止它,你可以' t 引用缺乏被禁止的东西。我的意思是,我可以从关于终生终结的部分复制/粘贴,但我看不出这会对任何事情产生重大影响。
    猜你喜欢
    • 2011-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    • 2017-01-11
    • 2013-03-21
    相关资源
    最近更新 更多