首页 > 解决方案 > 为什么让 operator new 私有中断 std::shared_ptr?

问题描述

我正在实现一个多态类型(称为它A),我想通过std::shared_ptr. 为了允许shared_from_this在派生类的构造函数中使用,A分配使用new,然后将成员初始化std::shared_ptr为自身以自动管理其生命周期。为了帮助实现这一点,我决定将特定类设为operator new私有,并计划使用create()辅助函数而不是newand make_shared。该设计可能看起来有点滑稽,但在我正在开发的 UI 库的上下文中是有意义的。一个最小的可重现示例如下:

struct A {
    A() : m_sharedthis(this) {

    }

    void destroy(){
        m_sharedthis = nullptr;
    }

    std::shared_ptr<A> self() const {
        return m_sharedthis;
    }

private:
    friend std::shared_ptr<A> create();

    std::shared_ptr<A> m_sharedthis;
};

std::shared_ptr<A> create(){
    auto a = new A();
    return a->self();
}

这可以编译并正常工作。当我将以下代码添加到的主体时出现问题A

struct A {
    ...
private:
    void* operator new(size_t size){
        return ::operator new(size);
    }
    void operator delete(void* ptr){
        ::operator delete(ptr);
    }
    ...
};

现在这无法在 MSVC 2017 上编译,并带有相当神秘的错误消息:

error C2664: 'std::shared_ptr<A>::shared_ptr(std::shared_ptr<A> &&) noexcept': cannot convert argument 1 from 'A *' to 'std::nullptr_t'
note: nullptr can only be converted to pointer or handle types

这里发生了什么?为什么构造函数只是突然std::shared_ptr尝试接受?nullptr

编辑:是的,在实际代码中,该类确实派生自std::enable_shared_from_this,但没有必要重现该错误。

标签: c++c++11shared-ptr

解决方案


当我尝试你的代码时,我得到了一个完全不同的错误:

error C2248: 'A::operator delete': cannot access private member declared in class 'A'

罪魁祸首是这个

m_sharedthis(this)

您提供了一个指针,但没有删除器。因此std::shared_ptr将尝试使用默认删除器,它可能包含delete您的类型的表达式。由于该删除器与您的课程无关,因此它无法访问 private operator delete

一种解决方法是提供自定义删除器

m_sharedthis(this, [](A* a) {delete a;})

已在类范围内定义的 lambda 可以operator delete在其定义点访问。

在一个无关的笔记上。您编写的代码将泄漏所有这些对象。既然对象都持有对自己的强引用,那么它们怎么会达到零引用计数呢?考虑std:enable_shared_from_this改用。


推荐阅读