使用共享指针访问单例 child class 时出现 SEGFAULT

SEGFAULT when accessing a singleton child class with shared pointer

我有模板classISingleton

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;
};

a parent class 和 Parent 的 child class 是单例

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 将导致段错误。我无法弄清楚这是继承问题还是单例本身的实现问题。谢谢指教!

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

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

中定义 class-specific operator delete
void operator delete(void *me) noexcept
{
    // Possibly assert(me == mInstance);
    mInstance = nullptr;
    ::operator delete(me);
}

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

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

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

因为你需要一个非拥有 shared_ptr,你可以使用一个空的删除器:

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

但将方法更改为不使用 shared_ptr 似乎更好。