这个Singleton类有什么问题吗?

时间:2016-10-07 17:39:35

标签: c++ singleton static-methods implementation

在这些情况下,我写了下一个Singleton类:
1 - 我想要一个且只有一个类的实例存在并且可以从整个游戏引擎访问 2 - Singleton被密集使用(每帧数千次)所以我不想写一个额外的GetInstance()函数,我试图避免任何额外的函数调用性能
3 - 一种可能性是让GetInstance()像这样内联:

inline Singleton* Singleton::GetInstance()
{
  static Singleton * singleton = new Singleton();
  return singleton;
}

但这会引起引用问题,每次调用都会有一个对单例的新引用,修复用c ++编写的内容:

class Singleton{
private:
    static   Singleton* singleton;
    Singleton(){}

public:
    static inline  Singleton* GetInstance() // now can be inlined !
    {
        return singleton;
    }

    static void Init()
    {
        // ofc i have to check first if  this function
        // is active only once
        if(singleton != nullptr)
        {
            delete singleton;
        }

        singleton = new Singleton();
    }

    ~Singleton(){} // not virtual because this class can't be inherited
};

Singleton* Singleton::singleton = nullptr;

此实施可能会遇到哪些问题?

4 个答案:

答案 0 :(得分:11)

您的第一个实施问题是您呼叫的唯一new泄漏。 以及强制用户检查指针有效性的签名。

由于您需要使用两步初始化,并且不禁止复制/移动/分配,您的第二个实现会出现更多问题。

只需使用Meyers'单:

class Singleton{
private:
    Singleton() = default;
    ~Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton operator&(const Singleton&) = delete;

public:
    static Singleton& GetInstance()
    {
        static Singleton instance;
        return instance;
    }
};

答案 1 :(得分:5)

除了@ Jarod42的回答之外,我想指出你也可以通过制作模板来实现一个通用的单例,并在CRTP类中使用它:

template<typename T>
class Singleton {
protected:
    Singleton() = default;
    ~Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton operator&(const Singleton&) = delete;

public:
    static T& instance() {
        static T instance;
        return instance;
    }
};

然后扩展它:

struct MySingleton : Singleton<MySingleton> { /* ... */ };

答案 2 :(得分:1)

考虑命名空间而不是单身人士!以下是我将如何做到这一点:

// thing.h
namespace thing {
// public interface
int doSomething();
}
// thing.cpp
namespace thing {

namespace {
// private data and functions can go right here :-)
int private_data_ = 1234;

int doSomethingInternal() {
    return private_data_ * 2;
}
}


// public interface
int doSomething() {
    return doSomethingInternal();
}
}

用法很简单:

int x = thing::doSomething();

不需要getInstance(),没有内存泄漏,也不会意外地发生多个实例。

答案 3 :(得分:-2)

  

但这会引起引用问题,每次调用都会有一个对单例的新引用

不正确的;相反,会有一个新的实例类与引用不同。你最有可能最终泄漏记忆。

static   Singleton* singleton;

使用unique_ptr代替原始指针。编译器优化无论如何都会将它转换为原始指针,但现在你清楚地告诉编译器它的生命周期应该是什么。

class Singleton{
  private :
  static   Singleton* singleton;

类的默认范围是私有的;你不需要说明私人范围。

Singleton(){}

如果类中没有其他构造函数,则无需提供空构造函数。

  

我试图避免任何额外的函数调用性能

编译的C ++通常会内联这些代码。

 inline  Singleton* GetInstance() // now can be inlined !

让它静止......?

 ~Singleton(){} // not virtual because this class can't be inherited

如果您的目的是使其不可继承,则在类声明中添加final关键字。然后,您可以删除析构函数。