草庐IT

c++ - 引用单例是在栈上还是在堆上?

coder 2024-02-21 原文

我在这里阅读了很多关于单例的文章,但没有一篇真正触及我的问题。我知道单例只应在需要时使用,并且在我的游戏中,我将它们用于引擎的特定部分。

也就是说,我最初将我的单例作为这样的指针:

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

但是我总是觉得使用太多指针对泄漏不利,如果可以的话我宁愿不使用它们(如果必须的话,我宁愿不使用它们(或智能指针)。所以我将我所有的单例更改为这样的引用:

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

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

我的问题是;引用单例是否都堆积在堆栈上?或者他们仍然在堆上分配?我应该使用智能指针将它们改回指针吗?

最佳答案

它几乎肯定不在堆上,因为它不是用 new 创建的。

但是,该标准对 static 变量的放置位置保持沉默,仅提及它们的行为。例如,C++11 3.7.1:

1/ All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program (3.6.2, 3.6.3).

2/ If a variable with static storage duration has initialization or a destructor with side effects, it shall not be eliminated even if it appears to be unused, except that a class object or its copy/move may be eliminated as specified in 12.8.

3/ The keyword static can be used to declare a local variable with static storage duration.

4/ The keyword static applied to a class data member in a class definition gives the data member static storage duration.

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

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

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


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

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

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

第二期只是养眼。不需要从 if block 中返回对象,因为它会在您到达函数底部时返回:

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

关于c++ - 引用单例是在栈上还是在堆上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25926407/

有关c++ - 引用单例是在栈上还是在堆上?的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  3. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  4. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  5. ruby-on-rails - Ruby 流量控制 : throw an exception, 返回 nil 还是让它失败? - 2

    我在思考流量控制的最佳实践。我应该走哪条路?1)不要检查任何东西并让程序失败(更清晰的代码,自然的错误消息):defself.fetch(feed_id)feed=Feed.find(feed_id)feed.fetchend2)通过返回nil静默失败(但是,“CleanCode”说,你永远不应该返回null):defself.fetch(feed_id)returnunlessfeed_idfeed=Feed.find(feed_id)returnunlessfeedfeed.fetchend3)抛出异常(因为不按id查找feed是异常的):defself.fetch(feed_id

  6. ruby - Chef LW 资源属性默认值如何引用另一个属性? - 2

    我正在尝试将一个资源属性的默认值设置为另一个属性的值。我正在为我正在构建的tomcat说明书定义一个资源,其中包含以下定义。我想要可以独立设置的“名称”和“服务名称”属性。当未设置服务名称时,我希望它默认为为“名称”提供的任何内容。以下不符合我的预期:attribute:name,:kind_of=>String,:required=>true,:name_attribute=>trueattribute:service_name,:kind_of=>String,:default=>:name注意第二行末尾的“:default=>:name”。当我在Recipe的新block中引用我

  7. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  8. ruby - 使用哪个,eruby 还是 erb? - 2

    eruby和erb有什么区别?哪些考虑因素会促使我选择其中之一?我的应用程序正在为网络设备(路由器、负载平衡器、防火墙等)生成配置文件。我的计划是对配置文件进行模板化,在源文件中使用嵌入式ruby​​(通过eruby或erb)来执行诸如迭代生成路由器的所有接口(interface)配置block之类的操作(这些block都非常相似,仅在标签上有所不同和IP地址)。例如,我可能有这样一个配置模板文件:hostnamesample-routerlogging10.5.16.26当通过嵌入式ruby​​解释器(erb或eruby)运行时,会产生以下输出:hostnamesample-rout

  9. ruby - 在 Ruby 中,为什么 Array.new(size, object) 创建一个由对同一对象的多个引用组成的数组? - 2

    如thisanswer中所述,Array.new(size,object)创建一个数组,其中size引用相同的object。hash=Hash.newa=Array.new(2,hash)a[0]['cat']='feline'a#=>[{"cat"=>"feline"},{"cat"=>"feline"}]a[1]['cat']='Felix'a#=>[{"cat"=>"Felix"},{"cat"=>"Felix"}]为什么Ruby会这样做,而不是对object进行dup或clone? 最佳答案 因为那是thedocumenta

  10. ruby - 引用具有指定索引的枚举器值 - 2

    假设我有一个可枚举对象enum,现在我想获取第三个项目。我知道一种通用方法是转换成数组,然后使用索引访问,如:enum.to_a[2]但这种方式会创建一个临时数组,效率可能很低。现在我使用:enum.each_with_index{|v,i|breakvifi==2}但这非常丑陋和多余。执行此操作最有效的方法是什么? 最佳答案 你可以使用take剥离前三个元素,然后剥离last从take给你的数组中获取第三个元素:third=enum.take(3).last如果您根本不想生成任何数组,那么也许:#Ifenumisn'tanEnum

随机推荐