当std :: make_shared分配的内存被释放时,std :: weak_ptrs是否会受到影响?

Kyl*_*tan 21 c++ memory

如果我调用std::make_shared<T>(而不是仅仅shared_ptr<T>显式分配),那么出于性能原因,我希望引用计数在T的实例旁边分配.一切都很好.

但是如果我有weak_ptr引用相同对象的实例,可能他们需要访问该引用计数,以了解该对象是否仍然存在.

因此,当T的实例的最后一个shared_ptr被销毁时,对系统的天真理解意味着它不能释放存储T的内存,因为weak_ptrs仍然需要访问该计数.

似乎有一个单独的弱引用计数器,理论上它可以与T的实例分开保存,这样T可以被破坏,内存释放,而弱引用仍然存在.但后来我们又回到了两个单独的分配,挫败了它的好处make_shared.

我想我在这里误解了一些东西.std::make_shared当存在弱引用时,如何释放为构造的实例分配的内存?

Jam*_*lis 13

如果您使用make_shared并且如果实现对对象和引用计数使用单个分配,则在释放所有引用(强和弱)之前,不能释放该分配.

但是,在释放所有强引用后,对象将被销毁(无论是否仍存在弱引用).

  • 不过这种打击弱指针的目的不是这样.与强指针相比,弱指针的关键在于强指针会延迟对象的释放.保持指向对象的弱指针应该是非常便宜的,但是如果它可以使整个对象粘在内存中,那么它非常昂贵. (6认同)
  • 最重要的是......你可以简单地不使用`make_shared`."make_shared"(就优化而言)的重点在于你正在做出选择.您需要单个分配而不是两个.这个选择有*后果*:如果你有弱引用,那么在所有弱引用都消失之前,单个分配将不会被清除.如果你不想要那个后果,那就不要使用`make_shared`. (4认同)
  • 我同意文档是这里的核心问题.make_shared导致内存挂起的时间更长,这很好,但需要仔细说明.否则,人们将无法理解他们正在做出的权衡. (4认同)
  • 理论上,免费商店可以接受内存的"部分返回".有点像收缩`reaclloc`.在实践中?可能不是. (3认同)
  • 有两个原因,它通常不像人们想象的那么大.首先,对于大多数大型物体,它们的大小不是由于它们的初始分配,而是后来附加在它们上面的东西.(例如,在地图,列表或向量中).这些将通过调用对象的析构函数来释放,因此它们不会挂起.其次,许多弱指针实现期望弱指针避免无限期地延迟对象*的破坏*.只要弱指针本身在对象消失后相对较快地被破坏,额外的内存使用将是短暂的. (3认同)
  • @Kylotan:不是我听过的任何"内存泄漏"的定义.内存泄漏是指您不再有权访问内存,因为您丢失了对它的所有引用.但是如果丢失了最后一个weak_ptr,则回收内存,不再分配内存. (2认同)
  • @Kylotan:"内存也是一种重要的资源,使用C++的一个原因(很多)是在对象破坏和内存释放之间存在密切关联." 我不同意; 重点是*决定论*:你知道什么时候发生的操作,你可以控制它们.在GC系统中,没有"对象破坏"(在终结器之外,通常要避免).GC会在任何时候删除内容.在C++中,您知道何时构造/销毁对象,以及何时分配/释放内存.你仍然可以用`weak_ptr`s控制它. (2认同)