如何使用 shared_ptr 来管理放置新放置的对象?

问题描述

我需要做的一件相当常见的事情是将一个对象和它想要的一些内存分配到一个严格传染的内存区域中:

class Thing{
    static_assert(alignof(Thing) == alignof(uint32),"party's over");
public:
   
    ~Thing(){
        //// if only,but this would result in the equivalent of `free(danglingPtr)` being called
        //// as the second stage of shared_ptr calling `delete this->get()`,which can't be skipped I believe? 
        // delete [] (char*)this;
    }

    static Thing * create(uint32 count) {
        uint32 size = sizeof(Thing) + sizeof(uint32) * count; // no alignment concerns
        char * data = new char[size];
        return new (data)Thing(count);
    }
    
    static void destroy(Thing *& p) {
        delete [] (char*)p;
        p = NULL;
    }

    uint32 & operator[](uint32 index) {
        assert(index < m_count);
        return ((uint32*)((char*)(this + sizeof(Thing))))[index];
    }

private:
    Thing(uint32 count) : m_count(count) {};
    uint32 m_count;
};

int main(){
    {
        auto p = shared_ptr<Thing>(Thing::create(1));
        // how can I tell p how to kill the Thing?
    }
    return 0;
}

Thing::Create() 中,这是通过将 new 放置到一段内存中来完成的。

在这种情况下,我还希望有一个共享指针来管理它,使用 auto p = shared_ptr<Thing>(Thing::create(1))。但是如果它在引用计数为空时调用 delete p.get() 的等价物,那将是未定义的,因为它与类型不匹配,更重要的是,将复数 new 与单数 delete 不匹配。我需要它以特殊方式删除

有没有办法在不定义外部函数的情况下轻松设置它?也许通过在引用计数为空时让共享指针调用 Thing::destroy() ?我知道共享指针可以接受“删除器”作为模板参数,但我不确定如何使用它,或者它是否是解决此问题的正确方法

解决方法

std::shared_ptr 接受删除器函数作为第二个参数,因此您可以使用它来定义如何销毁托管对象。

这是一个简化的例子:

class Thing
{
public:
    ~Thing()
    {
        std::cout << "~Thing\n";
    }

    static std::shared_ptr<Thing> create() {
        char * data = new char[sizeof(Thing)];
        Thing* thing = new (data) Thing{};
        return std::shared_ptr<Thing>{thing,&Thing::destroy};
    }
    
    static void destroy(Thing* p) {
        p->~Thing();
        delete [] (char*)p;
    }
};

int main()
{
    auto p = Thing::create();
}

Live Demo