gpt4 book ai didi

c++ - 对于使用C++ 20破坏运算符delete的非多态派生类,则为unique_ptr

转载 作者:行者123 更新时间:2023-12-02 09:47:46 26 4
gpt4 key购买 nike

C++ 20 销毁运算符delete 的新功能允许“钩住”对析构函数的调用,并用我们自己的操作“替换”它(例如,理论上,调用派生类的适当析构函数)。
是否可以使用销毁运算符delete来允许unique_ptr<A>保留指向A的实际非多态派生类的指针(即A中没有虚拟析构函数)而无需自定义删除器?

最佳答案

是的,有可能。实际上,它类似于P0722中提出的无vptrs的动态调度用例。
在C++ 20之前,需要使用unique_ptr<A>来保存指向A派生类的指针,或者:

  • A中的虚拟析构函数-或
  • 自定义删除器

  • C++ 20规范添加了新的删除运算符- destroying operator delete:如果静态类型不同于要删除的动态类型,则调用delete并不属于未定义的行为,如果选定的释放函数是销毁运算符delete,如 [expr.delete](§7.6.2.9/3)(重点我的)中所述:

    In a single-object delete expression, if the static type of the object to be deleted is different from its dynamic type and the selected deallocation function [...] is not a destroying operator delete, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. [...]


    因此,为此目的使用销毁运算符删除的选项是有效的。
    例如,如果我们知道 A永远不会被实例化,并且 unique_ptr<A>实际上总是持有 A_Proxy类型的指针,我们可以使用 static_cast在destroying运算符delete中执行下转换,并调用适当的析构函数(相同的方法可能是在自定义删除器中完成,现在可以将其删除)。
    class A {
    friend struct A_Proxy;
    std::string s; // just an example of a member managed at A's level
    A(const char* str): s(str) {}
    ~A() {}
    public:
    // Note: this is the destroying operator delete, as introduced in C++20
    void operator delete(A *p, std::destroying_delete_t);
    static std::unique_ptr<A> create(); // no need for a custom deleter
    void foo() const;
    };
    一个简单的派生类A_Proxy:
    struct A_Proxy: A {
    A_Proxy(): A("A_Proxy") {}
    ~A_Proxy() { /* do anything that is required at the proxy level */ }
    void foo() const {
    std::cout << "A_Proxy::foo()" << std::endl;
    }
    };
    随着 A的实现:
    void A::operator delete(A *p, std::destroying_delete_t) {
    // in this example we know for sure p is of type A_Proxy*
    ::delete static_cast<A_Proxy*>(p);
    // ^ call the global ::delete to avoid recursion
    }

    std::unique_ptr<A> A::create() {
    return std::make_unique<A_Proxy>(); // without the need for a custom deleter
    }

    void A::foo() const {
    static_cast<const A_Proxy*>(this)->foo();
    }
    主要:
    int main () {
    auto a = A::create();
    auto b = a.release();
    a = std::unique_ptr<A>(b);
    a->foo();
    }
    The code above - with a destroying operator delete

    但是要注意,这里没有真正的魔术。 使用自定义删除器将产生非常相似的代码。还要注意,即使不是全部,大多数 unique_ptr的实现都具有 stateless custom deleter的裸露指针大小,可用于此目的。
    The same code as above - but with a custom deleter
    <=请注意,此实现中带有自定义删除器的 unique_ptr的大小与裸指针相同。

    通过在基类中使用适当的类型标志,上述技术在涉及多个可能的强制转换的情况下也可能具有相关性,例如:
    void A::operator delete(A *p, std::destroying_delete_t) {
    if(p->type == "A") {
    ::delete p;
    }
    else if(p->type == "B") {
    ::delete static_cast<B*>(p);
    }
    else if(p->type == "C") {
    ::delete static_cast<C*>(p);
    }
    else {
    throw "unsupported type";
    }
    }
    和再次,这两种方法- destroying operator delete approachcustom deleter approach都将产生非常相似的代码,并且 unique_ptr的裸指针大小(在销毁运算符delete方法中, unique_ptr的大小为 ,确保的裸指针大小为自定义删除器方法 ,如果正确实现了删除器,并取决于unique_ptr的实际实现,则很有可能是)。

    关于c++ - 对于使用C++ 20破坏运算符delete的非多态派生类,则为unique_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63956218/

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