简体   繁体   English

RAII与垃圾收集器

[英]RAII vs. Garbage Collector

I recently watched a great talk by Herb Sutter about "Leak Free C++..." at CppCon 2016 where he talked about using smart pointers to implement RAII (Resource acquisition is initialization) - Concepts and how they solve most of the memory leaks issues. 我最近在CppCon 2016上观看了Herb Sutter关于“Leak Free C ++ ...”的精彩演讲,他谈到了使用智能指针实现RAII(资源获取是初始化) - 概念以及它们如何解决大多数内存泄漏问题。

Now I was wondering. 现在我在想。 If I strictly follow RAII rules, which seems to be a good thing, why would that be any different from having a garbage collector in C++? 如果我严格遵循RAII规则,这似乎是一件好事,为什么这与C ++中的垃圾收集器有什么不同呢? I know that with RAII the programmer is in full control of when the resources are freed again, but is that in any case beneficial to just having a garbage collector? 我知道使用RAII,程序员可以完全控制何时再次释放资源,但是在任何情况下都只对垃圾收集器有益吗? Would it really be less efficient? 它的效率真​​的会降低吗? I even heard that having a garbage collector can be more efficient, as it can free larger chunks of memory at a time instead of freeing small memory pieces all over the code. 我甚至听说有一个垃圾收集器可以更高效,因为它可以一次释放更大的内存块,而不是在代码中释放小内存块。

If I strictly follow RAII rules, which seems to be a good thing, why would that be any different from having a garbage collector in C++? 如果我严格遵循RAII规则,这似乎是一件好事,为什么这与C ++中的垃圾收集器有什么不同呢?

While both deal with allocations, they do so in completely different manners. 虽然两者都涉及分配,但它们以完全不同的方式进行。 If you are reffering to a GC like the one in Java, that adds its own overhead, removes some of the determinism from the resource release process and handles circular references. 如果您正在考虑使用Java中的GC,那会增加自己的开销,从资源释放过程中删除一些确定性并处理循环引用。

You can implement GC though for particular cases, with much different performance characteristics. 对于特定情况,您可以实现GC,具有不同的性能特征。 I implemented one once for closing socket connections, in a high-performance/high-throughput server (just calling the socket close API took too long and borked the throughput performance). 我在高性能/高吞吐量服务器中实现了一次关闭套接字连接(仅调用套接字关闭API花了太长时间并且提高了吞吐量性能)。 This involved no memory, but network connections, and no cyclic dependency handling. 这不涉及内存,而是网络连接,也没有循环依赖性处理。

I know that with RAII the programmer is in full control of when the resources are freed again, but is that in any case beneficial to just having a garbage collector? 我知道使用RAII,程序员可以完全控制何时再次释放资源,但是在任何情况下都只对垃圾收集器有益吗?

This determinism is a feature that GC simply doesn't allow. 这种确定性是GC根本不允许的功能。 Sometimes you want to be able to know that after some point, a cleanup operation has been performed (deleting a temporary file, closing a network connection, etc). 有时您希望能够知道在某一点之后,已执行清理操作(删除临时文件,关闭网络连接等)。

In such cases GC doesn't cut it which is the reason in C# (for example) you have the IDisposable interface. 在这种情况下,GC不会削减它,这就是C#(例如)你有IDisposable接口的原因。

I even heard that having a garbage collector can be more efficient, as it can free larger chunks of memory at a time instead of freeing small memory pieces all over the code. 我甚至听说有一个垃圾收集器可以更高效,因为它可以一次释放更大的内存块,而不是在代码中释放小内存块。

Can be ... depends on the implementation. 可以......取决于实施。

Garbage collection solves certain classes of resource problems that RAII cannot solve. 垃圾收集解决了RAII无法解决的某些类别的资源问题。 Basically, it boils down to circular dependencies where you do not identify the cycle before hand. 基本上,它归结为循环依赖关系,您不会事先识别循环。

This gives it two advantages. 这给它带来了两个好处。 First, there are going to be certain types of problem that RAII cannot solve. 首先,RAII无法解决某些类型的问题。 These are, in my experience, rare. 根据我的经验,这些是罕见的。

The bigger one is that it lets the programmer be lazy and not care about memory resource lifetimes and certain other resources you don't mind delayed cleanup on. 更大的一点是它让程序员变得懒惰而不关心内存资源的生命周期以及你不介意延迟清理的某些其他资源。 When you don't have to care about certain kinds of problems, you can care more about other problems. 当您不必关心某些类型的问题时,您可以关心其他问题。 This lets you focus on the parts of your problem you want to focus on. 这使您可以专注于您想要关注的问题部分。

The downside is that without RAII, managing resources whose lifetime you want constrained is hard. 不利的一面是,如果没有RAII,那么管理您想要约束的生命周期的资源就很难了。 GC languages basically reduce you to either having extremely simple scope-bound lifetimes or require you to do resource management manually, like in C, with manually stating you are done with a resource. GC语言基本上可以将您简化为具有极其简单的范围限制生命周期,或者要求您手动执行资源管理(如C语言),并手动说明您已完成资源。 Their object lifetime system is strongly tied to GC, and doesn't work well for tight lifetime management of large complex (yet cycle-free) systems. 它们的对象生命周期系统与GC密切相关,并且不适用于大型复杂(无循环)系统的严格生命周期管理。

To be fair, resource management in C++ takes a lot of work to do properly in such large complex (yet cycle-free) systems. 公平地说,C ++中的资源管理需要大量工作才能在如此大的复杂(无循环)系统中正常完成。 C# and similar languages just make it a touch harder, in exchange they make the easy case easy. C#和类似的语言只是让它变得更加难以接受,作为交换,它们使简单易用。

Most GC implementations also forces non-locality full fledged classes; 大多数GC实现也会强制非本地化的完整类; creating contiguous buffers of general objects, or composing general objects into one larger object, is not something that most GC implementations make easy. 创建一般对象的连续缓冲区,或将一般对象组合成一个更大的对象,并不是大多数GC实现变得容易的事情。 On the other hand, C# permits you to create value type struct s with somewhat limited capabilities. 另一方面,C#允许您创建具有有限功能的值类型struct In the current era of CPU architecture, cache friendliness is key, and the lack of locality GC forces is a heavy burden. 在当前的CPU架构时代,缓存友好性是关键,而GC部队缺乏局部性是一个沉重的负担。 As these languages have a bytecode runtime for the most part, in theory the JIT environment could move commonly used data together, but more often than not you just get a uniform performance loss due to frequent cache misses compared to C++. 由于这些语言大部分都具有字节码运行时,理论上JIT环境可以将常用数据一起移动,但是与C ++相比,由于频繁的缓存未命中,您通常会获得统一的性能损失。

The last problem with GC is that deallocation is indeterminate, and can sometimes cause performance problems. GC的最后一个问题是解除分配是不确定的,有时会导致性能问题。 Modern GCs make this less of a problem than it has been in the past. 与过去相比,现代地理信息系统使问题变得更少。

Notice that RAII is a programming idiom, while GC is a memory management technique. 请注意, RAII是一种编程习惯,而GC是一种内存管理技术。 So we are comparing apples with oranges. 所以我们将苹果与橙子进行比较。

But we can restrict RAII to its memory management aspects only and compare that to GC techniques. 但是,我们可以限制RAII 只有它的内存管理方面和比较,为GC技术。

The main difference between so called RAII based memory management techniques (which really means reference counting , at least when you consider memory resources and ignore the other ones such as files) and genuine garbage collection techniques is the handling of circular references (for cyclic graphs ). 所谓的基于RAII的内存管理技术(实际上意味着引用计数 ,至少在您考虑内存资源并忽略其他文件如文件时)和真正的垃圾收集技术之间的主要区别在于循环引用处理 (对于循环图 ) 。

With reference counting, you need to code specially for them (using weak references or other stuff). 使用引用计数,您需要专门为它们编码(使用弱引用或其他东西)。

In many useful cases (think of std::vector<std::map<std::string,int>> ) the reference counting is implicit (since it can only be 0 or 1) and is practically omitted, but the contructor and destructor functions (essential to RAII) behave as if there was a reference counting bit (which is practically absent). 在许多有用的情况下(想想std::vector<std::map<std::string,int>> )引用计数是隐式的(因为它只能是0或1)并且实际上是省略的,但是构造函数和析构函数(对RAII至关重要)的行为就好像有一个引用计数位(实际上不存在)。 In std::shared_ptr there is a genuine reference counter. std::shared_ptr有一个真正的引用计数器。 But memory is still implicitly manually managed (with new and delete triggered inside constructors and destructors), but that "implicit" delete (in destructors) gives the illusion of automatic memory management. 但是内存仍然是隐式 手动管理的 (使用newdelete触发内部构造函数和析构函数),但“隐式” delete (在析构函数中)给出了自动内存管理的错觉。 However, calls to new and delete still happen (and they cost time). 但是,仍然会发生对newdelete调用(并且它们需要花费时间)。

BTW the GC implementation may (and often does) handle circularity in some special way, but you leave that burden to the GC (eg read about the Cheney's algorithm ). BTW GC 实现可能(并且经常)以某种特殊方式处理循环,但是你将这个负担留给了GC(例如,阅读切尼的算法 )。

Some GC algorithms (notably generational copying garbage collector) don't bother releasing memory for individual objects, it is release en masse after the copy. 一些GC算法(尤其是代复制垃圾收集器)不要刻意为单个对象释放内存,它是释放连接的复印后集体 In practice the Ocaml GC (or the SBCL one) can be faster than a genuine C++ RAII programming style (for some , not all, kind of algorithms). 在实践中,Ocaml GC(或SBCL)可以比真正的C ++ RAII编程风格更快(对于某些 ,而不是所有类型的算法)。

Some GC provide finalization (mostly used to manage non-memory external resources like files), but you'll rarely use it (since most values consume only memory resources). 有些GC提供了最终化 (主要用于管理非内存外部资源,如文件),但您很少使用它(因为大多数值仅消耗内存资源)。 The disadvantage is that finalization does not offer any timing guarantee. 缺点是最终确定不提供任何时间保证。 Practically speaking, a program using finalization is using it as a last resort (eg closing of files should still happen more or less explicitly outside of finalization, and also with them). 实际上,使用finalization的程序正在使用它作为最后的手段(例如,文件的关闭仍应在最终确定之外或多或少明确地发生,并且还与它们一起)。

You still can have memory leaks with GC (and also with RAII, at least when used improperly), eg when a value is kept in some variable or some field but will never be used in the future. 您仍然可以使用GC(以及RAII,至少在使用不当时)内存泄漏,例如,当某个值保留在某个变量或某个字段中但将来永远不会使用时。 They just happen less often. 它们发生的频率较低。

I recommend reading the garbage collection handbook . 我建议阅读垃圾收集手册

In your C++ code, you might use Boehm's GC or Ravenbrook's MPS or code your own tracing garbage collector . 在您的C ++代码中,您可以使用Boehm的GCRavenbrook的MPS或编写您自己的跟踪垃圾收集器 Of course using a GC is a tradeoff (there are some inconvenience, eg non-determinism, lack of timing guarantees, etc...). 当然使用GC是一种权衡(存在一些不便,例如非确定性,缺乏时序保证等等)。

I don't think that RAII is the ultimate way of dealing with memory in all cases. 我不认为RAI​​I是在所有情况下处理记忆的最终方式。 In several occasions, coding your program in a genuinely and efficiently GC implementations (think of Ocaml or SBCL) can be simpler (to develop) and faster (to execute) than coding it with fancy RAII style in C++17. 在一些情况下,在真正有效的GC实现中编写程序(想想Ocaml或SBCL)可以比在C ++ 17中使用花哨的RAII样式编码更简单(开发)和更快(执行)。 In other cases it is not. 在其他情况下,它不是。 YMMV. 因人而异。

As an example, if you code a Scheme interpreter in C++17 with the fanciest RAII style, you would still need to code (or use) a explicit GC inside it (because a Scheme heap has circularities). 例如,如果您使用最高级的RAII样式在C ++ 17中编写Scheme解释器,您仍然需要在其中编码(或使用) 显式 GC(因为Scheme堆具有圆形)。 And most proof assistants are coded in GC-ed languages, often functional ones, (the only one I know which is coded in C++ is Lean ) for good reasons. 大多数证明助手都是用GC编辑的语言编写的,通常是功能性的语言(我知道唯一一个用C ++编写的语言是精益的 ),原因很充分。

BTW, I'm interested in finding such a C++17 implementation of Scheme (but less interested in coding it myself), preferably with some multi-threading ability. 顺便说一句,我有兴趣找到这样一个Scheme的C ++ 17实现(但对自己编码不太感兴趣),最好有一些多线程能力。

RAII and GC solve problems in completely different directions. RAII和GC在完全不同的方向上解决问题。 They are completely different, despite what some would say. 尽管有些人会说,但它们完全不同。

Both address the issue that managing resources is hard. 两者都解决了管理资源困难的问题。 Garbage Collection solves it by making it so that the developer doesn't need to pay as much attention to managing those resources. 垃圾收集通过制作它来解决它,以便开发人员不需要像管理这些资源那样多关注。 RAII solves it by making it easier for developers to pay attention to their resource management. RAII通过使开发人员更容易关注他们的资源管理来解决它。 Anyone who says they do the same thing has something to sell you. 任何说他们做同样事情的人都有卖给你的东西。

If you look at recent trends in languages, you're seeing both approaches being used in the same language because, frankly, you really need both sides of the puzzle. 如果你看看最近的语言趋势,你会发现这两种方法都使用相同的语言,因为坦白说,你真的需要这两个方面。 You're seeing lots of languages which use garbage collection of sorts so that you don't have to pay attention to most objects, and those languages also offer RAII solutions (such as python's with operator) for the times you really want to pay attention to them. 你会看到许多使用各种垃圾收集的语言,这样你就不必关注大多数对象了,这些语言也提供RAII解决方案(例如python's with operator),这是你真正想要关注的时候给他们。

  • C++ offers RAII through constructors/destructors and GC through shared_ptr (If I may make the argument that refcounting and GC are in the same class of solutions because they're both designed to help you not need to pay attention to lifespan) C ++通过构造函数/析构函数提供RAII,通过shared_ptr提供GC(如果我可以认为refcounting和GC属于同一类解决方案,因为它们都旨在帮助您不必关注生命周期)
  • Python offers RAII through with and GC through a refcounting system plus a garbage collector Python的通过提供RAII with通过引用计数系统,再加上一个垃圾收集器和GC
  • C# offers RAII through IDisposable and using and GC through a generational garbage collector C#通过IDisposable提供RAII,并通过分代垃圾收集器using GC

The patterns are cropping up in every language. 每种语言都出现了模式。

One of the problem about garbage collectors is that it's hard to predict program performance. 关于垃圾收集器的一个问题是很难预测程序性能。

With RAII you know that in exact time resource will go out of scope you will clear some memory and it will take some time. 使用RAII,您知道在准确的时间资源将超出范围,您将清除一些内存,这将需要一些时间。 But if you are not a master of garbage collector settings you cannot predict when cleanup will happen. 但是,如果您不是垃圾收集器设置的主人,则无法预测清理何时会发生。

For example: cleaning a bunch of small objects can be done more effectively with GC because it can free large chunk, but it will be not fast operation, and it's hard to predict when in will occur and because of "large chunk cleanup" it will take some processor time and can affect your program performance. 例如:使用GC可以更有效地清理一堆小对象,因为它可以释放大块,但是它不会快速运行,并且很难预测何时会发生并且由于“大块清理”它会占用一些处理器时间会影响程序性能。

Roughly speaking. 粗略地说。 The RAII idiom may be better for the latency and jitter . RAII习惯用于延迟抖动可能更好。 A garbage collector may be better for the system's throughput . 垃圾收集器可能更适合系统的吞吐量

"Efficient" is a very broad term, in sense of development efforts RAII is typically less efficient than GC, but in terms of performance GC is typically less efficient than RAII. “高效”是一个非常广泛的术语,在开发意义上,RAII通常效率低于GC,但就性能而言,GC通常比RAII效率低。 However it is possible to provide contr-examples for both cases. 但是,可以为这两种情况提供控制例子。 Dealing with generic GC when you have very clear resource (de)allocation patters in managed languages can be rather troublesome, just like the code using RAII can be surprisingly inefficient when shared_ptr is used for everything for no reason. 当您在托管语言中拥有非常清晰的资源(de)分配模式时处理通用GC可能会相当麻烦,就像使用RAII的代码在没有任何理由的情况下将shared_ptr用于所有内容时效率低得惊人。

The main part of the question about whether one or the other is "beneficial" or more "efficient" cannot be answered without giving lots of context and arguing about the definitions of these terms. 关于一个或另一个是“有益的”还是更“有效”的问题的主要部分在没有提供大量背景和争论这些术语的定义的情况下无法回答。

Beyond that, you can basically feel the tension of the ancient "Is Java or C++ the better language?" 除此之外,你基本上可以感受到古代“Java或C ++是更好的语言”的张力吗? flamewar crackling in the comments. 在评论中发出嘶嘶声。 I wonder what an "acceptable" answer to this question could look like, and am curious to see it eventually. 我想知道这个问题的“可接受”答案是什么样的,并且很想最终看到它。

But one point about a possibly important conceptual difference has not yet been pointed out: With RAII, you are tied to the thread that calls the destructor. 但是有一点关于可能重要的概念差异还没有被指出:使用RAII,你被绑定到调用析构函数的线程。 If your application is single threaded (and even though it was Herb Sutter who stated that The Free Lunch Is Over : Most software today effectively still is single-threaded), then a single core may be busy with handling the cleanups of objects that are no longer relevant for the actual program... 如果您的应用程序是单线程的(尽管Herb Sutter表示免费午餐已经结束 :今天大多数软件仍然单线程的),那么单个核心可能正忙着处理没有的对象的清理与实际计划相关的时间更长......

In contrast to that, the garbage collector usually runs in its own thread, or even multiple threads, and is thus (to some extent) decoupled from the execution of the other parts. 与此相反,垃圾收集器通常在其自己的线程中运行,甚至在多个线程中运行,因此(在某种程度上)与其他部分的执行分离。

(Note: Some answers already tried to point out application patterns with different characteristics, mentioned efficiency, performance, latency and throughput - but this specific point was not mentioned yet) (注意:一些答案已经尝试指出具有不同特征的应用程序模式,提到效率,性能,延迟和吞吐量 - 但这个特定点尚未提及)

Garbage collection and RAII each support one common construct for which the other is not really suitable. 垃圾收集和RAII每个都支持一个共同的构造,另一个不适合。

In a garbage-collected system, code may efficiently treat references to immutable objects (such as strings) as proxies for the data contained therein; 在垃圾收集系统中,代码可以有效地将对不可变对象(例如字符串)的引用视为其中包含的数据的代理; passing around such references is almost as cheap as passing around "dumb" pointers, and is faster than making a separate copy of the data for each owner, or trying to track ownership of a shared copy of the data. 传递这些引用几乎与传递“哑”指针一样便宜,并且比为每个所有者制作单独的数据副本或尝试跟踪数据的共享副本的所有权更快。 In addition, garbage-collected systems make it easy to create immutable object types by writing a class which creates a mutable object, populating it as desired, and providing accessor methods, all while refraining from leaking references to anything that might mutate it once the constructor finishes. 此外,垃圾收集系统通过编写创建可变对象的类,根据需要填充它并提供访问器方法,可以轻松创建不可变对象类型,同时避免在构造函数中泄漏引用可能会使其变异的任何内容饰面。 In cases where references to immutable objects need to be widely copied but the objects themselves don't, GC beats RAII hands down. 如果需要广泛复制对不可变对象的引用但对象本身不需要,则GC会击败RAII。

On the other hand, RAII is excellent at handling situations where an object needs to acquire exclusive services from outside entities. 另一方面,RAII非常适合处理对象需要从外部实体获取专有服务的情况。 While many GC systems allow objects to define "Finalize" methods and request notification when they are found to be abandoned, and such methods may sometimes manage to release outside services that are no longer needed, they are seldom reliable enough to provide a satisfactory way of ensuring timely release of outside services. 虽然许多GC系统允许对象定义“Finalize”方法并在发现它们被放弃时请求通知,并且这些方法有时可能设法释放不再需要的外部服务,但它们很少可靠,无法提供令人满意的方式。确保及时发布外部服务。 For management of non-fungible outside resources, RAII beats GC hands down. 为了管理不可替代的外部资源,RAII击败了GC。

The key difference between the cases where GC wins versus those where RAII wins is that GC is good at managing fungible memory that can be freed on an as-needed basis, but poor at handling non-fungible resources. GC获胜的案例与RAII获胜的案例之间的主要区别在于,GC擅长管理可根据需要释放的可替代内存,但处理不可替代的资源却很差。 RAII is good at handling objects with clear ownership, but bad at handling ownerless immutable data holders which have no real identity apart from the data they contain. RAII擅长处理具有明确所有权的对象,但不善于处理除了包含数据之外没有真正身份的无主不可变数据持有者。

Because neither GC nor RAII handles all scenarios well, it would be helpful for languages to provide good support for both of them. 由于GC和RAII都不能很好地处理所有场景,因此语言可以为这两种场景提供良好的支持。 Unfortunately, languages which focus on one tend to treat the other as an afterthought. 不幸的是,专注于一个语言的语言倾向于将另一个视为事后的想法。

RAII uniformly deals with anything that is describable as a resource. RAII统一处理可描述为资源的任何事物。 Dynamic allocations are one such resource, but they are by no means the only one, and arguably not the most important one. 动态分配就是这样一种资源,但它们绝不是唯一的,也可能不是最重要的资源。 Files, sockets, database connections, gui feedback and more are all things that can be managed deterministically with RAII. 文件,套接字,数据库连接,gui反馈等等都可以通过RAII确定性地进行管理。

GCs only deal with dynamic allocations, relieving the programmer of worrying about the total volume of allocated objects over the lifetime of the program (they only have to care about the peak concurrent allocation volume fitting) GC只处理动态分配,减轻了程序员在程序生命周期内担心分配对象总量的问题(他们只需关心峰值并发分配量拟合)

RAII and garbage collection are intended to solve different problems. RAII和垃圾收集旨在解决不同的问题。

When you use RAII you leave an object on the stack which sole purpose is to clean up whatever it is you want managed (sockets, memory, files, etc.) on leaving the scope of the method. 当您使用RAII时,您将一个对象留在堆栈上,其唯一目的是在离开方法范围时清理您想要管理的任何内容(套接字,内存,文件等)。 This is for exception-safety , not just garbage collection, which is why you get responses about closing sockets and freeing mutexes and the like. 这是为了异常安全 ,而不仅仅是垃圾收集,这就是为什么你得到关于关闭套接字和释放互斥锁等的响应。 (Okay, so no one mentioned mutexes besides me.) If an exception is thrown, stack-unwinding naturally cleans up the resources used by a method. (好吧,除了我之外没有人提到互斥锁。)如果抛出异常,堆栈展开自然会清除方法使用的资源。

Garbage collection is the programmatic management of memory, though you could "garbage-collect" other scarce resources if you'd like. 垃圾收集是对内存的程序化管理,但如果您愿意,可以“垃圾收集”其他稀缺资源。 Explicitly freeing them makes more sense 99% of the time. 明确地释放它们在99%的时间里更有意义。 The only reason to use RAII for something like a file or socket is you expect the use of the resource to be complete when the method returns. 将RAII用于类似文件或套接字的唯一原因是您希望在方法返回时使用资源。

Garbage collection also deals with objects that are heap-allocated , when for instance a factory constructs an instance of an object and returns it. 垃圾收集还处理堆分配的对象,例如工厂构造对象的实例并返回它。 Having persistent objects in situations where control must leave a scope is what makes garbage collection attractive. 在控制必须离开范围的情况下拥有持久对象是使垃圾收集具有吸引力的原因。 But you could use RAII in the factory so if an exception is thrown before you return, you don't leak resources. 但是您可以在工厂中使用RAII,因此如果在返回之前抛出异常,则不会泄漏资源。

I even heard that having a garbage collector can be more efficient, as it can free larger chunks of memory at a time instead of freeing small memory pieces all over the code. 我甚至听说有一个垃圾收集器可以更高效,因为它可以一次释放更大的内存块,而不是在代码中释放小内存块。

That's perfectly doable - and, in fact, is actually done - with RAII (or with plain malloc/free). 这是完全可行的 - 实际上,实际上已完成 - 使用RAII(或使用普通的malloc / free)。 You see, you don't necessarily always use the default allocator, which deallocates piecemeal only. 你看,你不一定总是使用默认的分配器,它只能零碎地分配。 In certain contexts you use custom allocators with different kinds of functionality. 在某些上下文中,您使用具有不同类型功能的自定义分配器。 Some allocators have the in-built ability of freeing everything in some allocator region, all at once, without having to iterate individual allocated elements. 一些分配器具有内置的能力,可以同时释放某些分配器区域中的所有内容,而无需迭代单个分配的元素。

Of course, you then get into the question of when to deallocate everything - whether the use of those allocators (or the slab of memory with which they're associated has to be RAIIed or not, and how. 当然,然后你会遇到什么时候解除所有内容的问题 - 是否使用那些分配器(或者与它们相关联的内存块是否必须是RAII,以及如何。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM