2

给大家带来两种不同的单例设计模式植入:

静态类成员

class SingletonCSM;
using SingletonCSMSp = std::shared_ptr < SingletonCSM > ;

class SingletonCSM
{
public:

    ~SingletonCSM()  { spInstance = nullptr; }

    static SingletonCSMSp GetInstance()
    {
        if (!spInstance)
            spInstance = std::make_shared<SingletonCSM>();

        return spInstance;
    }

private:

    SingletonCSM() {}

    // will be intilized in the cpp: SingletonCSMSp SingletonCSM::spInstance = nullptr;
    static SingletonCSMSp spInstance; 
};

静态成员变量

class SingletonFSV;
using SingletonFSVSp = std::shared_ptr < SingletonFSV > ;

class SingletonFSV
{
public:

    ~SingletonFSV() {}

    static SingletonFSVSp GetInstance()
    {
        static SingletonFSVSp spInstance = std::make_shared<SingletonFSV>();
        return spInstance;
    }

private:

    SingletonFSV() {}

};

我总是使用第一个 impl。SingletonCSM. 在我们的代码中,我遇到了一个 impl。像SingletonFSV

问题

  1. 我们可以同时考虑这两个 impl。作为一个有效的暗示。的设计模式?
  2. 两者在功能上是否相同?

动机

背景

SingletonFSV是作为 DLL 项目的一部分实现的。这个 DLL 编译在 中VS 2013,通过 exe 文件加载到内存中并运行。

问题

我已经升级VSVS 2015,编译了 DLL 项目并运行了 exe。突然,它崩溃了。在调试时,我注意到崩溃发生在 DLL 本身中。make_shared调用withingGetInstance()返回nullptr,自然会造成segmentation fault。

解决方案

我已经改变了SingletonFSVimpl。到SingletonCSM并且坠机停止了。make_shared返回了一个有效的指针,问题就解决了。

问题

我只是不明白问题是什么,为什么解决了?

4

1 回答 1

2

当您将static变量放入函数中时,它会在第一次调用该函数时创建,因此可以保证已将其实例化给该函数的所有调用者。

声明的成员static可以在调用函数之前或之后实例化,因为翻译单元之间的初始化顺序是未定义的。因此,全局对象或对象可以在运行时系统初始化静态成员之前static尝试访问它。

所以对于你的问题:

  1. 我们可以同时考虑这两个 impl。作为一个有效的暗示。的设计模式?
  2. 两者在功能上是否相同?

不,使用static成员是危险的,因为如果在调用之前没有进行初始化,调用者SingletonCSM::GetInstance()可以访问非创建的对象。nullptrfunction 方法是推荐的static方法,因为它保证每个调用者的初始化都已完成。

我只是不明白问题是什么,为什么解决了?

在您的情况下,转向更危险的方法似乎已经阻止了您的崩溃。我无法解释为什么会这样。但是您可能没有消除问题,可能是您在其他地方有未定义的行为,在这种情况下只是停止表现出来,但稍后可能会以不同的变化重新出现。

于 2016-09-21T12:49:00.630 回答