1

我总是阅读有关为智能指针行为重写新定义的可能性,但今天我仍然找不到一个真实的例子。

现在我想提出这个问题,看看能不能得到解决方案:

智能指针使用引用计数或引用链接来管理它们的生命周期,我的基本问题在于添加一个可能导致释放和删除我的指针的新状态,我想在触发事件时释放我的资源。

这或多或少就像在玩游戏时,通常当用户从关卡 1 到关卡 2 时,所有资源都会被加载和释放,所以当这种情况发生时,来自关卡 1 的资源会被释放。另外我想坚持这个例子,因为你不能等待自动引用计数,并且可能认为,如果在级别 2 中没有使用级别 1 的资源,它将被自动释放,因为它不再被请求; 这可能是真的,但是当用户在压力下使用机器时使用内存操作是一个非常糟糕的举动。

我想坚持使用智能指针,因为我也对它们提供的所有其他功能感兴趣,但它们对我来说有很大的缺点,我需要直接管理它们的生命周期。

我有什么选择?

4

4 回答 4

4

听起来您只是投入了一堆共享指针,而没有考虑正确考虑资源的所有权。从描述中我可以清楚地看出,关卡对象应该拥有所有这些资源。这意味着它们不应该被共享,因此根本不需要引用计数。

使用智能指针可以将您从在适当时间手动释放资源的负担中解放出来,但它并不能让您摆脱对适当时间的思考。

如果我是正确的并且级别应该拥有资源,请使用提供唯一所有权的智能指针,或者只使用自动对象,甚至不使用智能指针。除了需要访问这些对象的级别之外的所有其他对象都需要一个非拥有指针或对它的引用,即传统指针或引用。

如果我错了,资源确实应该共享,那么当关卡被销毁时它们不应该被释放:共享所有权的其他对象不会喜欢它。

于 2012-08-12T01:20:25.113 回答
3

如果您在关卡完成后仍有共享指针,那应该是因为共享指针没有作为自动变量分配在关卡生命周期内调用的函数堆栈上,而是被存储在某种类型的容器或一系列全球可访问的容器中。因此,您需要关注的主要问题是管理包含共享指针的容器的生命周期,这些共享指针管理每个级别的资源。

例如,在某个函数内部的堆栈上分配的智能指针foo的生命周期仅对应于函数调用的持续时间。一旦函数调用完成,共享指针就会被销毁。如果还有额外的共享指针仍然指向一个资源,那么资源本身不会被销毁,但是这些额外的共享指针需要驻留在被调用者的堆栈之外的其他位置。所以你的工作是管理那些“其他位置”,我猜这很可能是一些全球可访问的容器。

因此,刷新为每个级别管理数据的容器应该反过来完全破坏为每个级别分配的资源。如果需要,您可以使用事件驱动的接口或简单的观察者模式来触发容器的刷新,或者可以简单地由析构函数显式地为管理关卡资源生命周期的对象完成。

最后,尽管归结为资源管理......仅仅因为共享指针旨在防止内存泄漏并不意味着您不应该跟踪它们的分配方式或位置。如果您集中存储共享指针,那么销毁它们管理的资源将不是什么大问题。

于 2012-08-12T01:18:06.087 回答
3

如前所述,针对您的特定问题的共享指针可能不是正确的解决方案。但是,如果您想按时间划分释放关卡,您仍然可以手动管理它们的销毁(或者,如果内存压力不太高或存在问题,甚至可以在有一些空闲 CPU 周期时等待)。一旦你完成了一个资源,简单地将它排队等待销毁在一个全局队列(或几个队列,可能每个类型或按优先级等)。稍后只需处理该队列并删除引用。如果它确实是对它的最后引用,这将触发对象的销毁。例如,您可以轻松地每隔几次迭代检查一次计时器,并检查一旦您花费了 1 毫秒释放东西,退出并继续下一帧。

在性能方面,每个级别(或每个资产包)使用内存池更有意义。它使内存管理更容易,有时您可以立即释放整个池并跳过对其中的所有对象调用析构函数(如果您知道它们什么都不做!)。

于 2012-08-12T02:02:31.180 回答
2

听起来您根本不应该使用共享指针。有一些方法可以通过指定自定义释放器来覆盖行为,但我会考虑使用不同类型的“智能指针”。

Apache Web 服务器使用内存池通过让请求拥有一个内存池来释放与请求相关的所有资源。当您在服务器内部分配内存时,您需要确定要从中分配内存的池。服务器维护着几个内存池,每个内存池都有不同的生命周期——一个用于服务器实例,另一个用于模块,另一个用于每个请求,等等。这听起来更适合您的情况。

Apache 代码使用他们的Apache Portable Runtime进行内存管理。它是用 C 语言编写的,可能不适合您正在做的事情。看起来 Boost 也有一个内存池库,尽管我从未使用过它。

于 2012-08-12T01:44:10.777 回答