对象的共享所有权是否是糟糕设计的标志?

发布于 2024-08-16 05:24:44 字数 561 浏览 5 评论 0原文

背景:在阅读Dr. Stroustrup 的论文和常见问题解答,我注意到一些来自传奇 CS 科学家和程序员的强烈“意见”和很好的建议。其中之一是关于 C++0x 中的shared_ptr。他开始解释 shared_ptr 以及它如何表示所指向对象的共享所有权。在最后一行,他说,我引用

shared_ptr 代表共享 所有权,但共享所有权不是 我的理想:如果有一个物体就更好了 有明确的所有者和明确的, 可预测的使用寿命。

我的问题:RAII 在多大程度上替代了垃圾收集等其他设计模式?我假设手动内存管理不用于表示系统中的共享所有权。

Background: When reading Dr. Stroustrup's papers and FAQs, I notice some strong "opinions" and great advices from legendary CS scientist and programmer. One of them is about shared_ptr in C++0x. He starts explaining about shared_ptr and how it represents shared ownership of the pointed object. At the last line, he says and I quote:

. A shared_ptr represents shared
ownership but shared ownership isn't
my ideal: It is better if an object
has a definite owner and a definite,
predictable lifespan.

My Question: To what extent does RAII substitute other design patterns like Garbage Collection? I am assuming that manual memory management is not used to represent shared ownership in the system.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

彩虹直至黑白 2024-08-23 05:24:44

RAII 在多大程度上替代了垃圾收集等其他设计模式?我假设手动内存管理不用于表示系统中的共享所有权

嗯,使用 GC,您实际上不必考虑所有权。只要任何人需要它,该对象就会一直存在。共享所有权是默认的也是唯一的选择。

当然,一切都可以通过共享所有权来完成。但有时它会导致非常笨拙的代码,因为您无法控制或限制对象的生命周期。您必须使用 C# 的 using 块,或在 finally 子句中使用带有 close/dispose 调用的 try/finally 来确保对象得到清理当它超出范围时。

在这些情况下,RAII 更适合:当对象超出范围时,所有清理工作都应该自动进行。

RAII在很大程度上取代了GC。 99% 的情况下,共享所有权并不是您真正想要的理想状态。这是一个可以接受的妥协,但它并不真正符合您想要的。您希望资源在某个时候消失。不是之前,也不是之后。当 RAII 成为一个选项时,在这些情况下它会导致更优雅、简洁和健壮的代码。

但 RAII 并不完美。主要是因为它不能很好地处理偶尔不知道对象生命周期的情况。只要有人使用它,它就必须保留很长一段时间。但您不想永远保留它(或者只要范围围绕所有客户端,这可能只是主函数的全部)。

在这些情况下,C++ 用户必须“降级”到共享所有权语义,通常通过 shared_ptr 进行引用计数来实现。在这种情况下,GC 会胜出。它可以更稳健地实现共享所有权(例如,能够处理循环),并且更高效(与像样的 GC 相比,引用计数的摊销成本巨大

理想情况下,我想以一种语言看到两者。大多数时候,我想要 RAII,但偶尔,我有一个资源,我只想把它扔到空中,而不用担心它会在何时何地降落,只相信它会在它落地时被清理掉。这样做是安全的。

To what extent does RAII substitute other design patterns like Garbage Collection? I am assuming that manual memory management is not used to represent shared ownership in the system

Hmm, with GC, you don't really have to think about ownership. The object stays around as long as anyone needs it. Shared ownership is the default and the only choice.

And of course, everything can be done with shared ownership. But it sometimes leads to very clumsy code, because you can't control or limit the lifetime of an object. You have to use C#'s using blocks, or try/finally with close/dispose calls in the finally clause to ensure that the object gets cleaned up when it goes out of scope.

In those cases, RAII is a much better fit: When the object goes out of scope, all the cleanup should happen automatically.

RAII replaces GC to a large extent. 99% of the time, shared ownership isn't really what you want ideally. It is an acceptable compromise, in exchange for saving a lot of headaches by getting a garbage collector, but it doesn't really match what you want. You want the resource to die at some point. Not before, and not after. When RAII is an option, it leads to more elegant, concise and robust code in those cases.

RAII is not perfect though. Mainly because it doesn't deal that well with the occasional case where you just don't know the lifetime of an object. It has to stay around for a long while, as long as anyone uses it. But you don't want to keep it around forever (or as long as the scope surrounding all the clients, which might just be the entirety of the main function).

In those cases, C++ users have to "downgrade" to shared ownership semantics, usually implemented by reference-counting through shared_ptr. And in that case, a GC wins out. It can implement shared ownership much more robustly (able to handle cycles, for example), and more efficiently (the amortized cost of ref counting is huge compared to a decent GC)

Ideally, I'd like to see both in a language. Most of the time, I want RAII, but occasionally, I have a resource I'd just like to throw into the air and not worry about when or where it's going to land, and just trust that it'll get cleaned up when it's safe to do so.

药祭#氼 2024-08-23 05:24:44

程序员的工作是用他选择的语言优雅地表达事物。

C++ 对于堆栈上对象的构造和销毁具有非常好的语义。如果可以在作用域块的持续时间内分配资源,那么优秀的程序员可能会采取阻力最小的路径。对象的生命周期由大括号分隔,无论如何这些大括号可能已经存在。

如果没有好的方法将对象直接放入堆栈中,也许可以将其作为成员放入另一个对象中。现在它的生命周期更长了一些,但 C++ 仍然自动完成了很多工作。对象的生命周期由父对象界定——问题已被委托。

但可能没有一位父母。其次最好的事情是一系列养父母。这就是 auto_ptr 的用途。还是不错的,因为程序员应该知道所有者是哪个特定的父级。对象的生命周期由其所有者序列的生命周期限定。决定论和本身优雅的链条中的一个步骤是shared_ptr:生命周期由所有者池的联合界定。

但该资源可能不与系统中的任何其他对象、对象集或控制流并发。它是在某个事件发生时创建的,在另一个事件发生时销毁的。尽管有很多工具可以通过委托和其他生命周期来界定生命周期,但它们不足以计算任何任意函数。因此,程序员可能决定编写一个包含多个变量的函数来确定对象是存在还是消失,并调用 new 和 delete。

最后,编写函数可能很困难。也许管理对象的规则需要太多的时间和内存来实际计算!回到我最初的观点,优雅地表达它们可能真的很难。因此,我们有垃圾收集:对象的生命周期由您想要和不需要的时间来界定。


抱歉,我认为回答你的问题的最好方法是上下文:shared_ptr 只是一个计算对象生命周期的工具,它适合广泛的替代方案。当它起作用时它就起作用。应该在优雅的时候使用它。如果您的所有者数量少于一个池,或者您尝试使用它作为递增/递减的复杂方式来计算一些复杂的函数,则不应使用它。

The job of a programmer is to express things elegantly in his language of choice.

C++ has very nice semantics for construction and destruction of objects on the stack. If a resource can be allocated for the duration of a scope block, then a good programmer will probably take that path of least resistance. The object's lifetime is delimited by braces which are probably already there anyway.

If there's no good way to put the object directly on the stack, maybe it can be put inside another object as a member. Now its lifetime is a little longer, but C++ still doe a lot automatically. The object's lifetime is delimited by a parent object — the problem has been delegated.

There might not be one parent, though. The next best thing is a sequence of adoptive parents. This is what auto_ptr is for. Still pretty good, because the programmer should know what particular parent is the owner. The object's lifetime is delimited by the lifetime of its sequence of owners. One step down the chain in determinism and per se elegance is shared_ptr: lifetime delimited by the union of a pool of owners.

But maybe this resource isn't concurrent with any other object, set of objects, or control flow in the system. It's created upon some event happening and destroyed upon another event. Although there are a lot of tools for delimiting lifetimes by delegations and other lifetimes, they aren't sufficient for computing any arbitrary function. So the programmer might decide to write a function of several variables to determine whether an object is coming into existence or disappearing, and call new and delete.

Finally, writing functions can be hard. Maybe the rules governing the object would take too much time and memory to actually compute! And it might just be really hard to express them elegantly, getting back to my original point. So for that we have garbage collection: the object lifetime is delimited by when you want it and when you don't.


Sorry for the rant, but I think the best way to answer your question is context: shared_ptr is just a tool for computing the lifetime of an object, which fits into a broad spectrum of alternatives. It works when it works. It should be used when it's elegant. It should not be used if you have less than a pool of owners, or if you're trying to compute some sophisticated function using it as a convoluted way to increment/decrement.

楠木可依 2024-08-23 05:24:44

我的问题:RAII 在多大程度上替代了其他设计模式
喜欢垃圾收集吗?我假设手动内存管理
不用于表示系统中的共享所有权。

我不确定是否称其为设计模式,但在我同样强烈的观点中,仅谈论内存资源,RAII 解决了 GC 可以解决的几乎所有问题,同时引入的问题更少。

对象的共享所有权是糟糕设计的标志吗?

我同意这样的观点:在大多数情况下,共享所有权远非理想,因为高层设计并不一定需要它。我唯一一次发现它不可避免的是在持久数据结构的实现过程中,它至少被内化为实现细节。

我发现 GC 或共享所有权的最大问题是,当涉及到应用程序资源时,它并没有免除开发人员的任何责任,但会给人一种这样做的错觉。如果我们有这样的情况(Scene 是资源的唯一逻辑所有者,但其他事物持有指向它的引用/指针,例如存储用户定义的场景排除列表以省略的相机)渲染):

“在此处输入图像描述”"

假设应用程序资源就像图像,其生命周期与用户输入相关(例如:当用户请求关闭包含图像的文档时,应释放该图像),那么无论有没有 GC,正确释放资源的工作都是相同的。

如果没有 GC,我们可能会将其从场景列表中删除并允许调用其析构函数,同时触发事件以允许 Thing1Thing2Thing3 将指向它的指针设置为 null 或将它们从列表中删除,以便它们没有悬空指针。

对于 GC,基本上是一样的事情。我们从场景列表中删除资源,同时触发事件以允许 Thing1Thing2Thing3 将其引用设置为 null 或删除它们从列表中,以便垃圾收集器可以收集它。

隐藏的程序员错误

这种情况的不同之处在于,当程序员发生错误时会发生什么,例如 Thing2 未能处理删除事件。如果 Thing2 存储一个指针,它现在有一个悬空指针,我们可能会崩溃。这是灾难性的,但我们可能会在单元和集成测试中轻松捕获,或者至少 QA 或测试人员会很快捕获。我不在任务关键型或安全关键型环境中工作,因此,如果崩溃的代码设法以某种方式发布,如果我们能够获得错误报告、重现它、检测它并快速修复它,那也还不错。 。

如果 Thing2 存储强引用并共享所有权,我们就会遇到非常无声的逻辑泄漏,并且在 Thing2 被销毁之前映像不会被释放(这可能不会被销毁)销毁直至关闭)。在我的领域中,错误的这种无声性质是非常有问题的,因为即使在发货后,它也可能悄悄地被忽视,直到用户开始注意到在应用程序中工作一个小时会导致它占用千兆字节的内存,例如,并开始减慢速度直到他们重新启动它。到那时,我们可能已经积累了大量此类问题,因为它们很容易像隐形战斗机错误一样在雷达下飞行,而且没有什么比隐形战斗机错误更让我讨厌的了。

正是由于这种沉默的本质,我倾向于不喜欢热情地共享所有权,而且说实话,我从来不明白为什么 GC 如此受欢迎(可能是我的特定领域——我承认我非常无知 那些对任务至关重要的语言,例如)以至于我渴望没有 GC 的新语言。我发现调查与共享所有权相关的所有此类泄漏非常耗时,有时调查几个小时才发现泄漏是由我们无法控制的源代码(第三方插件)引起的。

弱引用

概念上讲,弱引用对于 Thing1Thing2Thing3 来说是理想的选择。这将使他们能够事后检测到资源何时被破坏,而无需延长其生命周期,也许我们可以保证在这些情况下发生崩溃,或者有些人甚至可以事后优雅地处理这种情况。对我来说,问题是弱引用可以转换为强引用,反之亦然,因此在内部和第三方开发人员中,有人仍然可能不小心在 Thing2 中存储强引用,即使弱引用会更合适。

我过去确实尝试鼓励内部团队尽可能多地使用弱引用,并记录它应该在 SDK 中使用。不幸的是,在如此广泛和混合的人群中推广这种做法是很困难的,而且我们最终仍然遇到了逻辑漏洞。

任何人在任何给定时间都可以通过简单地在其对象中存储对某个对象的强引用来延长该对象的生命周期,这种情况在俯视大量泄漏的庞大代码库时开始变得非常可怕。资源。我经常希望需要一种非常明确的语法来将任何类型的强引用存储为某种对象的成员,这至少会导致开发人员在不必要地这样做时三思而后行。

显式销毁

因此,我倾向于对持久性应用程序资源进行显式销毁,如下所示:

on_removal_event:
    // This is ideal to me, not trying to release a bunch of strong
    // references and hoping things get implicitly destroyed.
    destroy(app_resource);

...因为我们可以依靠它来释放资源。我们不能完全保证系统中的某些东西最终不会有悬空指针或弱引用,但至少这些问题在测试中往往很容易检测和重现。它们不会长期被忽视并不断积累。

对我来说,一个棘手的情况一直是多线程。在这些情况下,我发现有用的而不是成熟的垃圾收集,或者说,shared_ptr,是以某种方式简单地延迟销毁:

on_removal_event:
    // *May* be deferred until threads are finished processing the resource.
    destroy(app_resource);

在某些持久线程以某种方式统一的系统中,它们有一个处理事件,例如,当线程没有被处理时,我们可以在一个时间片中以延迟的​​方式标记要销毁的资源(几乎开始感觉像停止世界GC,但我们保留明确的破坏)。在其他情况下,我们可能会使用引用计数,但要避免使用 shared_ptr,其中资源的引用计数从零开始,并且将使用上面的显式语法进行销毁,除非线程在本地扩展其资源通过临时增加计数器的生命周期(例如:在本地线程函数中使用作用域资源)。

尽管看起来很迂回,但它避免了将 GC 引用或 shared_ptr 暴露给外界,这很容易诱使某些开发人员(团队内部或第三方开发人员)存储强引用 (shared_ptr,例如)作为像 Thing2 这样的对象的成员,从而无意中延长了资源的生命周期,并且可能比适当的时间长得多(可能一直持续到应用程序关闭)。

RAII

同时,RAII 和 GC 一样自动消除物理泄漏,而且它不仅适用于内存,还适用于其他资源。我们可以将它用于作用域互斥体,这是一个在破坏时自动关闭的文件,我们甚至可以使用它通过作用域防护等自动逆转外部副作用。

因此,如果有选择,我必须选择一个,这很容易RAII 对我来说。我工作的领域中,由共享所有权引起的无声内存泄漏绝对是致命的,如果(并且很可能)在测试过程中尽早发现悬空指针崩溃,那么实际上更可取。即使在一些非常模糊的事件中,它被晚了,如果它表现为靠近发生错误的站点的崩溃,这仍然比使用内存分析工具并试图找出谁忘记释放引用而费力地处理数百万个引用更好。代码行数。在我非常直率的观点中,GC 带来的问题比它为我的特定领域解决的问题还要多(VFX,在场景组织和应用程序状态方面与游戏有些相似),除了那些非常无声的共享所有权泄漏之外,原因之一是因为它会给开发人员一种错误的印象,即他们不必考虑持久性应用程序资源的资源管理和所有权,同时无意中导致左右逻辑泄漏。

“RAII 何时会失败”

在我的整个职业生涯中,我遇到的唯一一个我想不出任何可能的方法来避免某种共享所有权的情况是当我实现一个持久数据结构库时,如下所示:

< a href="https://i.sstatic.net/BkfEe.png" rel="nofollow noreferrer">输入图像描述这里

我用它来实现一个不可变的网格数据结构,该结构可以修改部分而不使其变得唯一,如下所示(使用 400 万个四边形进行测试):

net/6FTje.gif" rel="nofollow noreferrer">在此处输入图像描述

每一个帧,当用户在其上拖动并雕刻它时,就会创建新的网格。不同之处在于,新的网格是强引用部分,而不是通过画笔使其唯一,因此我们不必复制所有顶点、所有多边形、所有边等。不可变版本忽略了线程安全、异常安全,非破坏性编辑、撤消系统、实例化等。

在这种情况下,不可变数据结构的整个概念围绕共享所有权,以避免复制不唯一的数据。这是一个真实的案例,无论如何我们都无法避免共享所有权(至少我想不出任何可能的方法)。

这是我遇到的唯一可能需要 GC 或引用计数的情况。其他人可能也遇到过一些自己的情况,但根据我的经验,非常非常少的情况真正需要在设计层面共享所有权。

My Question: To what extent does RAII substitute other design patterns
like Garbage Collection? I am assuming that manual memory management
is not used to represent shared ownership in the system.

I'm not sure about calling this a design pattern, but in my equally strong opinion, and just talking about memory resources, RAII tackles almost all the problems that GC can solve while introducing fewer.

Is shared ownership of objects a sign of bad design?

I share the thought that shared ownership is far, far from ideal in most cases, because the high-level design doesn't necessarily call for it. About the only time I've found it unavoidable is during the implementation of persistent data structures, where it's at least internalized as an implementation detail.

The biggest problem I find with GC or just shared ownership in general is that it doesn't free the developer of any responsibilities when it comes to application resources, but can give the illusion of doing so. If we have a case like this (Scene is the sole logical owner of the resource, but other things hold a reference/pointer to it like a camera storing a scene exclusion list defined by the user to omit from rendering):

enter image description here

And let's say the application resource is like an image, and its lifetime is tied to user input (ex: the image should be freed when the user requests to close a document containing it), then the work to properly free the resource is the same with or without GC.

Without GC, we might remove it from a scene list and allow its destructor to be invoked, while triggering an event to allow Thing1, Thing2, and Thing3 to set their pointers to it to null or remove them from a list so that they don't have dangling pointers.

With GC, it's basically the same thing. We remove the resource from the scene list while triggering an event to allow Thing1, Thing2, and Thing3 to set their references to null or remove them from a list so that the garbage collector can collect it.

The Silent Programmer Mistake Which Flies Under Radar

The difference in this scenario is what happens when a programmer mistake occurs, like Thing2 failing to handle the removal event. If Thing2 stores a pointer, it now has a dangling pointer and we might have a crash. That's catastrophic but something we might easily catch in our unit and integration tests, or at least something QA or testers will catch rather quickly. I don't work in a mission-critical or security-critical context, so if the crashy code managed to ship somehow, it's still not so bad if we can get a bug report, reproduce it, and detect it and fix it rather quickly.

If Thing2 stores a strong reference and shares ownership, we have a very silent logical leak, and the image won't be freed until Thing2 is destroyed (which it might not be destroyed until shutdown). In my domain, this silent nature of the mistake is very problematic, since it can go quietly unnoticed even after shipping until users start to notice that working in the application for an hour causes it to take gigabytes of memory, e.g., and starts slowing down until they restart it. And at that point, we might have accumulated a large number of these issues, since it's so easy for them to fly under the radar like a stealth fighter bug, and there's nothing I dislike more than stealth fighter bugs.

enter image description here

And it's due to that silent nature that I tend to dislike shared ownership with a passion, and TBH I never understood why GC is so popular (might be my particular domain -- I'm admittedly very ignorant of ones that are mission-critical, e.g.) to the point where I'm hungry for new languages without GC. I have found investigating all such leaks related to shared ownership to be very time-consuming, and sometimes investigating for hours only to find the leak was caused by source code outside of our control (third party plugin).

Weak References

Weak references are conceptually ideal to me for Thing1, Thing2, and Thing3. That would allow them to detect when the resource has been destroyed in hindsight without extending its lifetime, and perhaps we could guarantee a crash in those cases or some might even be able to gracefully deal with this in hindsight. The problem to me is that weak references are convertible to strong references and vice versa, so among the internal and third party developers out there, someone could still carelessly end up storing a strong reference in Thing2 even though a weak reference would have been far more appropriate.

I did try in the past to encourage the use of weak references as much as possible among the internal team and documenting that it should be used in the SDK. Unfortunately it was difficult to promote the practice among such a wide and mixed group of people, and we still ended up with our share of logical leaks.

The ease at which anyone, at any given time, can extend the lifetime of an object far longer than appropriate by simply storing a strong reference to it in their object starts to become a very frightening prospect when looking down at a huge codebase that's leaking massive resources. I often wish that a very explicit syntax was required to store any kind of strong reference as a member of an object of a kind which at least would lead a developer to think twice about doing it needlessly.

Explicit Destruction

So I tend to favor explicit destruction for persistent application resources, like so:

on_removal_event:
    // This is ideal to me, not trying to release a bunch of strong
    // references and hoping things get implicitly destroyed.
    destroy(app_resource);

... since we can count on it to free the resource. We can't be completely assured that something out there in the system won't end up having a dangling pointer or weak reference, but at least those issues tend to be easy to detect and reproduce in testing. They don't go unnoticed for ages and accumulate.

The one tricky case has always been multithreading for me. In those cases, what I have found useful instead of full-blown garbage collection or, say, shared_ptr, is to simply defer destruction somehow:

on_removal_event:
    // *May* be deferred until threads are finished processing the resource.
    destroy(app_resource);

In some systems where the persistent threads are unified in a way such that they have a processing event, e.g., we can mark the resource to be destroyed in a deferred fashion in a time slice when threads are not being processed (almost starts to feel like stop-the-world GC, but we're keeping explicit destruction). In other cases, we might use, say, reference counting but in a way that avoids shared_ptr, where a resource's reference count starts at zero and will be destroyed using that explicit syntax above unless a thread locally extends its lifetime by incrementing the counter temporarily (ex: using a scoped resource in a local thread function).

As roundabout as that seems, it avoids exposing GC references or shared_ptr to the outside world which can easily tempt some developers (internally on your team or a third party developer) to store strong references (shared_ptr, e.g.) as a member of an object like Thing2 and thereby extend a resource's lifetime inadvertently, and possibly for far, far longer than appropriate (possibly all the way until application shutdown).

RAII

Meanwhile RAII automatically eliminates physical leaks just as well as GC, but furthermore, it works for resources other than just memory. We can use it for a scoped mutex, a file which automatically closes on destruction, we can use it even to automatically reverse external side effects through scope guards, etc. etc.

So if given the choice and I had to pick one, it's easily RAII for me. I work in a domain where those silent memory leaks caused by shared ownership are absolutely killer, and a dangling pointer crash is actually preferable if (and it likely will) be caught early during testing. Even in some really obscure event that it's caught late, if it manifests itself in a crash close to the site where the mistake occurred, that's still preferable than using memory profiling tools and trying to figure out who forgot to release a reference while wading through millions of lines of code. In my very blunt opinion, GC introduces more problems than it solves for my particular domain (VFX, which is somewhat similar to games in terms of scene organization and application state), and one of the reasons besides those very silent shared ownership leaks is because it can give the developers the false impression that they don't have to think about resource management and ownership of persistent application resources while inadvertently causing logical leaks left and right.

"When does RAII fail"

The only case I've ever encountered in my whole career where I couldn't think of any possible way to avoid shared ownership of some sort is when I implemented a library of persistent data structures, like so:

enter image description here

I used it to implement an immutable mesh data structure which can have portions modified without being made unique, like so (test with 4 million quadrangles):

enter image description here

Every single frame, a new mesh is being created as the user drags over it and sculpts it. The difference is that the new mesh is strong referencing parts not made unique by the brush so that we don't have to copy all the vertices, all the polygons, all the edges, etc. The immutable version trivializes thread safety, exception safety, non-destructive editing, undo systems, instancing, etc.

In this case the whole concept of the immutable data structure revolves around shared ownership to avoid duplicating data that wasn't made unique. It's a genuine case where we cannot avoid shared ownership no matter what (at least I can't think of any possible way).

That's about the only case where we might need GC or reference counting that I've encountered. Others might have encountered some of their own, but from my experience, very, very few cases genuinely need shared ownership at the design level.

猫九 2024-08-23 05:24:44

垃圾收集是一种设计模式吗?我不知道。

共享所有权的一大优势是其固有的可预测性。使用 GC,资源回收不再由您掌控。这就是重点。它何时以及如何发生通常不在使用它的开发人员的考虑范围内。通过共享所有权,您拥有控制权(请注意,有时过多的控制权是一件坏事)。假设您的应用程序向 X 生成了一百万个共享指针。所有这些都是您所做的,您对它们负责,并且您可以完全控制何时创建和销毁这些引用。因此,一个坚定而细心的程序员应该准确地知道谁引用了什么以及引用了多长时间。如果你想销毁一个对象,你必须销毁它的所有共享引用,而中提琴,它就消失了。

这对于开发实时软件的人来说会带来一些深远的影响,因为实时软件必须是完全可预测的。这也意味着你可以用看起来非常像内存泄漏的方式来伪造。我个人不想成为一个坚定而细心的程序员,当我不需要的时候(笑吧,我想去野餐和骑自行车,不计算我的参考文献),所以在适当的情况下,GC是我的首选路线。我编写了一些实时声音软件,并使用共享引用来可预测地管理资源。

您的问题:RAII 什么时候会失败? (在共享参考文献的上下文中)
我的回答:当你无法回答这个问题时:谁可以参考这个?当所有权的恶性循环发展时。

我的问题:GC什么时候会失败?
我的答案是:当您想要完全控制和可预测性时。当GC是Sun Microsystems在最后一刻赶到最后期限时编写的,并且具有荒谬的行为时,这些行为只能由从微软借来的喝得酩酊大醉的原始人类代码猴子设计和实现。

我的观点:我认为 BS 对于清晰的设计非常认真。显然,在一个地方销毁资源通常比在多个地方销毁资源的设计更清晰。

Is Garbage Collection a Design Pattern? I don't know.

The big advantage of shared ownership, is its inherent predictability. With GC the reclamation of resources is out of your hands. Thats the point. When, and how it happens is usually not on the mind of the developer using it. With shared ownership, you are in control (beware, sometimes too much control is a bad thing). Lets say your app spawns off a million shared_ptr's to X. All of those are your doing, you are responsible for them and you have total control over when those references are created and destroyed. So a determined and careful programmer should know exaclty who references what and for how long. If you want an object to be destroyed, you have to destroy all the shared references to it, and viola, it's gone.

This carries some profound consequences for people who make realtime software, which MUST be totally predictable. This also means you can fudge up in ways that look an awful lot like memory leaks. I personally don't want to be a determined and careful programmer when I don't have to be (go ahead and laugh, I want to go on picnics and bike rides, not count my references), so where appropriate GC is my prefered route. I have written a little bit of realtime sound software, and used shared references to manage resources predictably.

Your question: When does RAII fail? (In the context of shared references)
My Answer: When you can't answer the question: who may have a reference to this? When vicious insipid circles of ownership develop.

My question: When does GC fail?
My answer: When you want total control and predictability. When the GC is the written by Sun Microsystems in a last minute dash to deadline and has ridiculous behaviors which could only have been designed and implemented by severely drunk protohuman code monkeys borrowed from Microsoft.

My opinion: I think BS is just really serious about clear design. It seems obvious that having one place where resources are destroyed is usually a clearer design than having many places where they might destroyed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文