使用共享指针访问单例子类时的SEGFAULT

SEGFAULT when accessing a singleton child class with shared pointer

本文关键字:子类 SEGFAULT 单例 访问 共享 指针      更新时间:2023-10-16

我有一个模板类ISingleton

class ISingleton
{
public:
    static T* getInstance()
    {
        lock_guard<mutex> guard(mMutex);
        if (mInstance == NULL)
        {
            mInstance = new T();
        }
        return mInstance;
    }
    static void destroy()
    {
        lock_guard<mutex> guard(mMutex);
        delete mInstance;
        mInstance = NULL;
    }
    ISingleton(ISingleton const&) = delete;
    ISingleton& operator =(ISingleton const&) = delete;
protected:
    ISingleton()
    {
    }
    virtual ~ISingleton()
    {
    }
private:
    static T* mInstance;
    static mutex mMutex;
};

CCD_ 2的父类和子类

class Parent
{
    public:
        Parent(string name) { mName = name; }
        virtual ~Parent();
        string getName(){ return mName; }
    private:
        string mName;
}
class Child : public Parent, public ISingleton<Child>
{
    public:
        virtual ~Child();
    private:
        Child() { mName = "child"; }
        friend ISingleton<Child>;
};

我创建了一个指向像这样的单例的共享指针

void foo()
{
    shared_ptr<Parent> module(Child::getInstance());
}
Parent *c = Child::getInstance();
c->getName(); //SEGFAULT

如果shared_ptr'的引用计数达到零,就会出现问题。对Child::getName的下一次调用将导致segfault。我不知道这是继承问题还是单例本身的实现问题。谢谢你的建议!

您所做的并不是C++中的单例。单例永远不会被破坏和重新创建,因此将其存储在智能指针中毫无意义。

但如果你想用智能指针销毁它,你需要告诉智能指针如何做。默认情况下,智能指针调用operator delete。您可以在ISingleton:中定义类特定的operator delete

void operator delete(void *me) noexcept
{
    // Possibly assert(me == mInstance);
    mInstance = nullptr;
    ::operator delete(me);
}

或者,您可以为智能指针提供一个lambda,它将调用destroy而不是delete:

std::shared_ptr<Parent> module(Child::getInstance(),
        [](Parent*){ Child::destroy(); });

您不应该将singleton地址添加到智能指针中,因为它是拥有资源的singleton。

由于您需要一个非拥有shared_ptr,您可以使用一个空的deleter:

std::shared_ptr<Parent> dummy_ptr(Child::getInstance(), [](Parent*){/*Nothing*/});

但将方法改为不服用CCD_ 11似乎更好。