我一直在阅读有关为智能指针行为重写新定义的可能性,但至今仍无法找到真实的例子。
现在我想提出这个问题,看看能否找到解决方案:
智能指针正在使用引用计数或引用链接来管理它们的生命周期,我的基本问题在于添加一个可以导致释放和删除指针的新状态,我想在事件发生时释放我的资源触发。
这或多或少与玩游戏时一样,当用户从1级传递到2级时,通常会加载和释放所有资源,因此当发生这种情况时,将释放1级资源。另外我想坚持这个例子,因为你不能等待自动引用计数,并且可能认为,如果在级别2中没有使用级别1的资源,它将被自动释放,因为它不再被请求;这可能是真的,但当用户在压力下使用机器时使用内存是一个非常糟糕的举动。
我想坚持使用智能指针,因为我也对它们提供的所有其他功能感兴趣,但它们对我来说有很大的缺点,我需要直接管理它们的生命周期。
我有哪些选择?
答案 0 :(得分:4)
听起来你刚刚投入了大量的共享指针,并没有考虑适当的资源所有权。从描述中可以清楚地看出,关卡对象应该拥有所有这些资源。这意味着他们应该不被共享,因此根本不需要引用计数。
使用智能指针可以让您免于在适当的时间手动释放资源的负担,但这并不能让您无法考虑适当的时间。
如果我是正确的并且level应该拥有资源,请使用提供唯一所有权的智能指针,或者只使用自动对象,甚至不用智能指针。除了需要访问这些对象的级别之外的所有其他对象都需要非拥有指针或对它的引用,即传统的指针或引用。
如果我错了并且确实应该共享资源,那么在销毁级别时不应该释放它们:共享所有权的其他对象将不喜欢它。
答案 1 :(得分:3)
如果你在一个关卡完成后仍然有共享指针,那应该是因为共享指针没有被分配为在关卡生命期间调用的函数堆栈上的自动变量,但是而是存储在某种类型的容器或一系列全局可访问的容器中。因此,您需要关注的主要问题是管理包含管理每个级别资源的共享指针的容器的生命周期。
例如,在某个函数foo
内的堆栈上分配的智能指针只有一个与函数调用持续时间相对应的生命周期。函数调用完成后,共享指针就会被销毁。如果还有其他共享指针仍然指向资源,那么资源本身不会被破坏,但是那些额外的共享指针需要驻留在被调用者堆栈以外的其他位置。因此,您的工作是管理那些“其他位置”,我猜这些位置很可能是一系列全球可访问的容器。
因此,刷新管理每个级别数据的容器应该完全破坏每个级别的已分配资源。如果需要,可以使用事件驱动的接口或简单的观察者模式来触发容器的刷新,或者可以简单地由析构函数显示管理级别资源生命周期的对象。
最后虽然归结为资源管理......仅仅因为共享指针旨在防止内存泄漏并不意味着您不应该跟踪它们的分配方式和位置。如果集中存储共享指针,那么销毁他们管理的资源就不会那么大。
答案 2 :(得分:3)
如前所述,针对您的特定问题的共享指针可能不是正确的解决方案。但是,你仍然可以手动管理它们的破坏,例如你想要时间分层释放你的等级(或者如果内存压力不是太高或者有问题,甚至可能等待你有一些备用CPU周期)。完成资源后,简单地将其排队以便在全局队列(或多个队列,每个类型或优先级等等)中进行销毁。稍后只需处理该队列并删除引用。如果它确实是对象的最后引用,这将触发对象的破坏。例如,您可以轻松地每隔几次迭代检查一次计时器,并检查一旦您花了1ms的时间释放东西,退出并继续下一帧。
性能方面,每个级别(或每个资产包)使用内存池更有意义。它使内存管理更容易,你有时可以立即释放整个池,并跳过调用内部所有对象的析构函数(如果你知道它们什么都不做!)。
答案 3 :(得分:2)
听起来你真的不应该使用共享指针。有一些方法可以通过指定自定义解除分配器来覆盖行为,但我会考虑使用不同类型的“智能指针”。
Apache Web服务器使用内存池通过让请求拥有内存池来释放与请求关联的所有资源。在服务器内部分配内存时,需要标识要从中分配的池。服务器维护一些内存池,每个内存池具有不同的生命周期 - 一个用于服务器实例,另一个用于模块,另一个用于每个请求等。这听起来更符合您的情况。
Apache代码使用他们的Apache Portable Runtime进行内存管理。它是用C语言编写的,可能不是您正在做的最佳匹配。它确实看起来像Boost有一个内存池库,虽然我从未使用它。