引用单例是在堆栈上还是在堆上

Does a reference singleton go on the stack or the heap?

本文关键字:单例 堆栈 引用      更新时间:2023-10-16

我在这里读了很多关于单身汉的文章,但没有一篇真正涉及到我的问题。我知道Singleton应该只在需要的时候使用,在我的游戏中,我将它们用于引擎的特定部分。

也就是说,我最初把我的单身汉当作这样的指针:

static MapReader* Instance()
{
    if (instance == 0)
    {
        instance = new MapReader();
        return instance;
    }
    return instance;
}

然而,我总是觉得使用太多的指针对泄漏不利,如果我能帮助的话,我宁愿不使用它们(如果必须的话,也可以使用智能指针)。所以我把我所有的单身汉都改成了这样的参考:

static MapReader& Instance()
{
    static MapReader instance;
    return instance;
}

然而,现在我注意到我的游戏有时会滞后,然后加速,就像FPS有点不稳定一样。

我的问题是;引用singleton是否都堆积在堆栈上?还是它们仍然被分配到堆中?我应该用智能指针把它们改回指针吗?

由于它不是用new创建的,所以几乎可以肯定它不在堆上。

然而,该标准对中放置static变量的地方保持沉默,只提到了它们的行为例如,参见C++11 3.7.1:

1/所有不具有动态存储持续时间、不具有线程存储持续时间和非本地的变量都具有静态存储持续时间。这些实体的存储应在程序期间持续(3.6.2、3.6.3)。

2/如果具有静态存储持续时间的变量具有初始化或具有副作用的析构函数,则即使它看起来未使用,也不应将其删除,除非类对象或其复制/移动可以按照12.8的规定删除。

3/关键字static可用于声明具有静态存储持续时间的局部变量。

4/类定义中应用于类数据成员的关键字static为数据成员提供静态存储持续时间。

这几乎就是标准本身强加给他们的程度。

大多数实现可能都有一个与堆和堆栈分离的区域,用于存储静态存储持续时间的变量。

几乎可以肯定的是,静态和引用的使用也不会减慢代码的速度。在深入研究了编译器及其工作方式后,静态变量的速度往往与其他变量一样快,因为它们在内存中的定位速度非常快。


顺便说一句,singleton的指针变体有两个问题。如果您在线程环境中工作,第一种情况是潜在的竞争条件。如果不同的线程调用Instance(),则可能会创建多个对象。

具体来说,如果线程A进入if语句,那么线程B开始运行,B就可以通过,创建一个对象然后返回。如果A继续,它将创建一个对象。

如果您是单线程的,或者您只从一个线程创建实例,或者您在其他线程运行之前创建实例,那么应该没问题。

第二期只是养眼药。不需要从if块中返回对象,因为当你到达函数的底部时,它会被返回:

static MapReader* Instance() {
    if (instance == 0)
        instance = new MapReader();
    return instance;
}

两者都没有。函数内部的静态变量位于数据部分。对于记录,函数外的静态变量和全局变量也是如此。