<p>RAII, the acronym for &quot;resource acquisition is initialization&quot;, is a crucial paradigm of C++ that is meant to prevent the following things:</p>
<ul>
<li>Forgetting to free a dynamic storage</li>
<li>Forgetting to close a file</li>
<li>Forgetting to unlock a mutex</li>
</ul>
<p>Though C++ fails to <em>completely</em> prevent these caveats for many reasons, I'm coming up with a way for perfectly obeying RAII. The idea is to basically to render the objects in question as primitive types, and to offer syntaxes and semantics for ensuring safety. (Namely, the said syntaxes and semantics I've come up with are the notion of <strong>scoped variable declaration</strong>, but its explicit demonstration is out of the scope of this question.)</p>
<p>But are there any RAII-requiring notions whose safety issues are parallel to the three listed situations above?</p>

<language-design><c++><declarations><memory-safety>
What is the explicit list of the situations that require RAII?
CC BY-SA 4.0
2024-06-24T10:18:59.360Z
As Kate Gregory said, RAII is a bad name for what should be called "scope-based resource management"
Jonathan
CC BY-SA 4.0
2024-06-24T13:03:34.287Z
@Jonathan: I think it's more that RAII is a very C++ specific term for scope-based resource management. Within C++, it's perfectly sensible, outside of that context not so much.
Jack Aidley
CC BY-SA 4.0
2024-06-24T15:10:50.543Z
So are you reinventing Java's try-with-resource?
feldentm
CC BY-SA 4.0
2024-06-24T15:30:06.610Z
There are no situations that _require_ RAII, and there is an unbounded list of situations where it might be a good idea.
OrangeDog
CC BY-SA 4.0
2024-06-25T13:22:54.120Z
Resource management constrained to a scope inside a function, with RAII or with `using` or similar, works. Things get complicated when resources need to escape function scope. That's one thing Rust ownership mechanics tries to (help to) solve, and you can see it's not trivial.
Pablo H
<p>You should basically <em>never</em> write code that requires you to write <em>corresponding</em> code later in the control flow.</p>
<p>The obvious examples are resource acquisition things like allocating memory (you have to free it later) or opening a file (you have to close it later), and there are lots of other examples provided around this question.</p>
<p>The problem is that when you do this, you make a <em>hidden rule</em> that, in order to maintain your code correctly, whenever you change the code in one place, you have to change the code in the other place in a corresponding way.  In fact, <em>all</em> the code that might affect the opened/closed, allocated/free or whatever status needs to be maintained as a single unit, even though it could be spread out across the code base.</p>
<p>That is a recipe for bugs, and these bugs used to happen <em>all the time</em>.</p>
<p>Now, these kinds of bugs hardly ever happen, because professional C++ programmers always use use RAII to make sure there are no hidden correspondences like that.</p>
<p>If you acquire a resource or do something else that needs to be cleaned up later, then the code that does that should also ensure that it gets cleaned up automatically, at the appropriate time, as variables that refer to that resource go out of scope.</p>
<p>This is a very general rule.  It doesn't make sense to ask for an exhaustive list of all the things that require RAII, because the list is endless, and programmers need to be able to create their own.</p>
<p>I use RAII when generating XML, for example, to ensure that if I write a start tag, then I will also write the corresponding end tag at some point.  That sort of thing is not going to be on anybody's pre-written list of &quot;RAII situations&quot;.</p>

CC BY-SA 4.0
2024-06-24T14:11:11.640Z
2024-06-24T14:19:50.770Z
2024-06-24T14:19:50.770Z
Matt Timmermans
CC BY-SA 4.0
2024-06-26T00:24:42.013Z
The "corresponding code" phrase is a nice generalization. One can even omit the "later in the control flow": Iterators, for example, obviate the need to adapt loops to array lengths defined elsewhere. Polymorphism lets one extend class hierarchies without adapting code elsewhere. -- Suddenly RAII appears as a form of eliminating redundancy.
Peter - Reinstate Monica
CC BY-SA 4.0
2024-06-26T03:34:44.677Z
> Iterators, for example, obviate the need to adapt loops to array lengths defined elsewhere.

Most code in C that I've seen just uses a constant for the array size, so you never really need to update the loops
CoffeeTableEspresso
CC BY-SA 4.0
2024-06-26T08:25:27.757Z
@CoffeeTableEspresso a constant is still code
Caleth
CC BY-SA 4.0
2024-06-26T13:14:37.840Z
@Caleth my point is it's code in one single place, not an update to every single loop. So it's not really in the same category as a lot of the other examples (imo).
CoffeeTableEspresso
CC BY-SA 4.0
2024-06-26T14:58:29.370Z
@CoffeeTableEspresso the name of the constant is in at least two places: the array declaration and the loop. One of those places can be changed to a different name without the other. And if most of the C you have seen uses constants for array sizes, you haven't seen much C. Loads of C I have seen has dynamic arrays
Caleth
CC BY-SA 4.0
2024-06-26T15:34:54.670Z
@Caleth how often are you changing the name of the size of the array? And even if you are, it's an easy fix (since it will be a compile time error if you change it in one spot and not the other). This is a very different case from the other examples, where there are usually no compile time checks for forgetting to update the other places in code that need updating
CoffeeTableEspresso
CC BY-SA 4.0
2024-06-26T15:41:49.110Z
@CoffeeTableEspresso `int SomeArray[SomeConstantA]; int OtherArray[SomeConstantA];` gets changed to `int SomeArray[SomeConstantB]; int OtherArray[SomeConstantA];` and someone misses one of the uses of `SomeConstantA` in looping over `SomeArray`. No compile time failure.
Caleth
<p>There are no things that <em>require</em> RAII to exist, (as evidenced by various languages not having it). RAII helps in avoiding resource management bugs but is not required to solve the resource management problem as a whole.</p>
<p>Though having some way to tie a cleanup action to a scope is very useful. This is the <code>defer</code> statement as found in Go and Odin and D's (<code>scope(exit)</code>), the finally clause in Java, or the <code>with</code> statement in python or the try-with-resources in java. 2 out of the 3 actions you listed can be solved with something like that rather than a RAII local.</p>
<p>Adding RAII to a language brings in some complications, you now need to account for 4 ways of moving an object; from a source that can/cannot be clobbered (copy vs. move) to a destination that is not yet/already &quot;alive&quot;, (assign vs. construct).</p>

CC BY-SA 4.0
2024-06-24T08:34:35.380Z
2024-06-26T07:38:31.290Z
2024-06-26T07:38:31.290Z
ratchet freak
CC BY-SA 4.0
2024-06-24T11:28:40.723Z
Do note that `defer`/`scope(exit)`/`finally` are pretty good for _scope bound_ variables, but not as good when the resources are _transferred_, because they're tied to the variable, not the resource itself.
Matthieu M.
CC BY-SA 4.0
2024-06-26T00:19:37.720Z
But then I dearly missed RAII in C# (as well as copy semantics, which may indicate I was operating under the wrong paradigm).
Peter - Reinstate Monica
<ul>
<li>Forgetting to unregister an event in the C# style of event system.</li>
</ul>
<p>But if your language has weakrefs, you automatically solve this before calling it RAII. If it doesn't, but depends on other garbage collectors, because this reference exists, the event callback target is never freed, so it can never unregister automatically. If it doesn't, and objects could be unmanaged, you may have other memory safety problems.</p>
<ul>
<li>Forgetting to revert changes in backtracking algorithms.</li>
</ul>
<p>For example, in the internal implementation of regex, one should not expose information in unmatched paths. Depending on how you implement this, it may cover all side effects and extend the scope of this problem by too much.</p>

CC BY-SA 4.0
2024-06-24T10:14:17.700Z
2024-06-24T10:14:17.700Z
user23013
CC BY-SA 4.0
2024-06-26T03:36:01.930Z
I'm not sure how weakrefs solve the problem?
CoffeeTableEspresso
CC BY-SA 4.0
2024-06-26T08:27:56.837Z
@CoffeeTableEspresso the event only holds a weak ref to the object that registered, so the next time the event is raised after that object is collected, the event can unregister it
Caleth
CC BY-SA 4.0
2024-06-26T10:28:22.910Z
Weakrefs generally don't solve the same problem as RAII, because with GC you usually have no guarantee of *promptness*. RAII and similar mechanisms have well-defined cleanup time, whereas an orphan weakref may linger *indefinitely* until the GC finalises it. Memory pressure is different from resource pressure, and a GC triggers only on the former. Critically, in many runtimes GC finalisation may never run if memory is not exhausted or the program shuts down.
MisterMiyagi
CC BY-SA 4.0
2024-06-26T13:16:37.477Z
@Caleth you don't have guarantees of WHEN the clean-up code runs, which is a critical component of RAII.
CoffeeTableEspresso
CC BY-SA 4.0
2024-06-26T13:23:27.350Z
@CoffeeTableEspresso yeah, you can have a zombie event handler. It solves the problem of events being a resource leak. Even with RAII, you have to write the event system in such a way that an object subscribing to an event holds on to the subscription, so that it can unsubscribe on destruction, which often means everything inheriting from a base `Object` type
Caleth
CC BY-SA 4.0
2024-06-26T14:43:47.377Z
@Caleth I disagree with you that it handles the problem. Say I'm listening on a specific port. In many cases I'd like to be able to immediately reuse that port, but I can't if it may take an arbitrary amount of time until that port is available again. RAII solves this for me, weakrefs do not.
CoffeeTableEspresso
CC BY-SA 4.0
2024-06-26T14:44:03.430Z
@Caleth I'm also not fully understanding your second point. I use RAII all the time, I've never had to worry about inheriting from `Object`, and it's never been particularly complicated as you seem to be making it out to be
CoffeeTableEspresso
CC BY-SA 4.0
2024-06-26T14:53:28.307Z
@CoffeeTableEspresso for a raii event registration, you have to hold onto *something* to deregister when you are destroyed. At scale, that is going to be "everything that listens to events derives from `Object` because `~Object()` deregisters" or "everything that listens to events is owned by a `shared_ptr`, with the event holding a `weak_ptr`" or some similar global restriction, because the alternatives are a recipe for leaks or dangling handlers
Caleth
CC BY-SA 4.0
2024-06-26T15:10:08.337Z
@Caleth You only hold onto whatever you "registered with", be it a resource representation, an event loop, an event handler, or whatever. You *don't* hold onto everything that listens to anything. At least, in any sane programming language or resource framework. Holding onto everything is what leads to leaks!
MisterMiyagi
CC BY-SA 4.0
2024-06-26T15:28:33.173Z
@MisterMiyagi either `event.register(this, ...args)` requires you to call `event.unregister(this)`, or it returns an object that you have to keep alive. Both of those things require somewhere to hold onto that something.
Caleth
CC BY-SA 4.0
2024-06-26T15:30:01.000Z
@Caleth I have `EventRegisterer er{this, ...};`. The constructor registers it, the destructor unregisters it. I implement that class once, and then just use an instance of it whenever I need to register/unregister an event.
CoffeeTableEspresso
CC BY-SA 4.0
2024-06-26T15:34:40.827Z
@CoffeeTableEspresso yes. but that still means that `er` has to live somewhere. In a small scale project it might be fine for each class to have a data member for each event it ever listens to, but I'd prefer a `std::vector<EventRegisterer>` in some base class
Caleth
CC BY-SA 4.0
2024-06-26T15:36:02.460Z
@Caleth yes that's the whole point of RAII. I keep `er` around so I can control exactly when it's created/destroyed
CoffeeTableEspresso
CC BY-SA 4.0
2024-06-26T15:38:35.350Z
@CoffeeTableEspresso and you still have the issue that there are *two* lifetimes that `er` has to be shorter than: the listener and the emitter
Caleth
CC BY-SA 4.0
2024-06-26T17:22:12.043Z
@Caleth The event handler has to live *at least as long as* everything that is registered on it. Which is trivially done by GC. What isn’t done trivially by GC is both the listener and emitter being registered only for *as short as needed*, which can indeed be much shorter than the lifetime (which, as mentioned, can be indefinite depending on the GC strategy and situation). GC takes care of the upper bound, but RAII takes care of the lower bound.
MisterMiyagi
CC BY-SA 4.0
2024-06-26T20:55:20.863Z
@Caleth Years ago, I was asked to debug an issue where, when the heap of a Java application was increased, the database connection pool would run out of connections. The issue was that connections were leaked on exceptions. The DB connection pool was using weak-refs to clean up leaked connections on GC. When the heap was increased, GC ran less often, resulting in the pool running out of connections.
JimmyJames
<p>The general notion of resources should be better thought of as a responsibility.  An entity acquires a responsibility when it asks some other entity to change its behavior, to the detriment of some other entities, <em>until further notice</em>; after having issued the request, the entity that issues it has a responsibility to ensure that the appropriate notice will be given.</p>
<p>A memory manager may be asked &quot;please refrain from allowing anyone else to use this memory until I say I'm done with it&quot;.  A file manager may be asked &quot;please refrain from allowing anyone else to use this file, and to the extent possible defer updating the version on disk, until I say I'm done with it&quot;.  A database may be asked &quot;please refrain from allowing anyone to access record X until I say I'm done with it.&quot;.</p>
<p>Instead of trying to think in low-level terms about files, memory, and so on, it's far better to recognize the high level concept of responsibility to deliver notice, since that underlies almost all &quot;resource cleanup&quot; patterns.</p>
<p>BTW, a feature that is all too often missing in RAII-style constructs is a means of distinguishing normal and abnormal circumstances for giving notice.  If code which is editing a database record throws an exception, having the responsibility wrapper notify the database that the transaction has been abandoned would be useful, but if the controlled block exits without having either committed or rolled back the transaction, it would often be more useful to throw an &quot;improperly abandoned transaction&quot; exception.  The abandonment of the transaction shouldn't cause a double-exception fault, but it should throw an exception in situations that would otherwise represent &quot;normal&quot; release.</p>

CC BY-SA 4.0
2024-06-24T15:21:14.457Z
2024-06-24T15:21:14.457Z
supercat
<p>There is no complete list, because many of the most &quot;interesting&quot; examples are application-specific.</p>
<p>Consider something like transaction safety in a database server: a transaction must either 100% happen or 100% not happen, even if an exception is thrown. Committing or rolling back a transaction in progress is often handled by RAII in database servers written in C++.</p>
<p>The three examples that you gave are usually irrelevant if the program is exiting; memory and file handles will all be cleaned up by the operating system, so doing it manually may be wasting the user's time. Indeed, flushing I/O buffers are probably more important than closing file handles.</p>
<p>But application-specific &quot;resources&quot;, such as persistent transaction safety, are usually not.</p>

CC BY-SA 4.0
2024-06-24T02:13:00.893Z
2024-06-24T02:13:00.893Z
Pseudonym
CC BY-SA 4.0
2024-06-24T15:13:11.187Z
Also closing communication channels may involve sending exit messages. You are only right about the OS collecting them wrt. the underlying resources, not the protocols.
feldentm
# What is the explicit list of the situations that require RAII?
Posted by: username_0 on 2024-06-24
RAII, the acronym for "resource acquisition is initialization", is a crucial paradigm of C++ that is meant to prevent the following things:

* Forgetting to free a dynamic storage
* Forgetting to close a file
* Forgetting to unlock a mutex

Though C++ fails to *completely* prevent these caveats for many reasons, I'm coming up with a way for perfectly obeying RAII. The idea is to basically to render the objects in question as primitive types, and to offer syntaxes and semantics for ensuring safety. (Namely, the said syntaxes and semantics I've come up with are the notion of **scoped variable declaration**, but its explicit demonstration is out of the scope of this question.)

But are there any RAII-requiring notions whose safety issues are parallel to the three listed situations above?
**Tags:** language-design c++ declarations memory-safety
> **Comments:**
> **username_1**: As Kate Gregory said, RAII is a bad name for what should be called "scope-based resource management"  
> **username_2**: @Jonathan: I think it's more that RAII is a very C++ specific term for scope-based resource management. Within C++, it's perfectly sensible, outside of that context not so much.  
> **username_3**: So are you reinventing Java's try-with-resource?  
> **username_4**: There are no situations that _require_ RAII, and there is an unbounded list of situations where it might be a good idea.  
> **username_5**: Resource management constrained to a scope inside a function, with RAII or with `using` or similar, works. Things get complicated when resources need to escape function scope. That's one thing Rust ownership mechanics tries to (help to) solve, and you can see it's not trivial.  
---
## 5 answers
### Answer by username_16 on 2024-06-24. Score: 20 | Accepted answer
There is no complete list, because many of the most "interesting" examples are application-specific.

Consider something like transaction safety in a database server: a transaction must either 100% happen or 100% not happen, even if an exception is thrown. Committing or rolling back a transaction in progress is often handled by RAII in database servers written in C++.

The three examples that you gave are usually irrelevant if the program is exiting; memory and file handles will all be cleaned up by the operating system, so doing it manually may be wasting the user's time. Indeed, flushing I/O buffers are probably more important than closing file handles.

But application-specific "resources", such as persistent transaction safety, are usually not.
> **Comments:**
> **username_3** (2024-06-24): Also closing communication channels may involve sending exit messages. You are only right about the OS collecting them wrt. the underlying resources, not the protocols.  
---
### Answer by username_6 on 2024-06-24. Score: 16
You should basically *never* write code that requires you to write *corresponding* code later in the control flow.

The obvious examples are resource acquisition things like allocating memory (you have to free it later) or opening a file (you have to close it later), and there are lots of other examples provided around this question.

The problem is that when you do this, you make a *hidden rule* that, in order to maintain your code correctly, whenever you change the code in one place, you have to change the code in the other place in a corresponding way. In fact, *all* the code that might affect the opened/closed, allocated/free or whatever status needs to be maintained as a single unit, even though it could be spread out across the code base.

That is a recipe for bugs, and these bugs used to happen *all the time*.

Now, these kinds of bugs hardly ever happen, because professional C++ programmers always use use RAII to make sure there are no hidden correspondences like that.

If you acquire a resource or do something else that needs to be cleaned up later, then the code that does that should also ensure that it gets cleaned up automatically, at the appropriate time, as variables that refer to that resource go out of scope.

This is a very general rule. It doesn't make sense to ask for an exhaustive list of all the things that require RAII, because the list is endless, and programmers need to be able to create their own.

I use RAII when generating XML, for example, to ensure that if I write a start tag, then I will also write the corresponding end tag at some point. That sort of thing is not going to be on anybody's pre-written list of "RAII situations".
> **Comments:**
> **username_7** (2024-06-26): The "corresponding code" phrase is a nice generalization. One can even omit the "later in the control flow": Iterators, for example, obviate the need to adapt loops to array lengths defined elsewhere. Polymorphism lets one extend class hierarchies without adapting code elsewhere. -- Suddenly RAII appears as a form of eliminating redundancy.  
> **username_8** (2024-06-26): > Iterators, for example, obviate the need to adapt loops to array lengths defined elsewhere.

Most code in C that I've seen just uses a constant for the array size, so you never really need to update the loops  
> **username_9** (2024-06-26): @CoffeeTableEspresso a constant is still code  
> **username_8** (2024-06-26): @Caleth my point is it's code in one single place, not an update to every single loop. So it's not really in the same category as a lot of the other examples (imo).  
> **username_9** (2024-06-26): @CoffeeTableEspresso the name of the constant is in at least two places: the array declaration and the loop. One of those places can be changed to a different name without the other. And if most of the C you have seen uses constants for array sizes, you haven't seen much C. Loads of C I have seen has dynamic arrays  
> **username_8** (2024-06-26): @Caleth how often are you changing the name of the size of the array? And even if you are, it's an easy fix (since it will be a compile time error if you change it in one spot and not the other). This is a very different case from the other examples, where there are usually no compile time checks for forgetting to update the other places in code that need updating  
> **username_9** (2024-06-26): @CoffeeTableEspresso `int SomeArray[SomeConstantA]; int OtherArray[SomeConstantA];` gets changed to `int SomeArray[SomeConstantB]; int OtherArray[SomeConstantA];` and someone misses one of the uses of `SomeConstantA` in looping over `SomeArray`. No compile time failure.  
---
### Answer by username_10 on 2024-06-24. Score: 14
There are no things that *require* RAII to exist, (as evidenced by various languages not having it). RAII helps in avoiding resource management bugs but is not required to solve the resource management problem as a whole.

Though having some way to tie a cleanup action to a scope is very useful. This is the `defer` statement as found in Go and Odin and D's (`scope(exit)`), the finally clause in Java, or the `with` statement in python or the try-with-resources in java. 2 out of the 3 actions you listed can be solved with something like that rather than a RAII local.

Adding RAII to a language brings in some complications, you now need to account for 4 ways of moving an object; from a source that can/cannot be clobbered (copy vs. move) to a destination that is not yet/already "alive", (assign vs. construct).
> **Comments:**
> **username_11** (2024-06-24): Do note that `defer`/`scope(exit)`/`finally` are pretty good for _scope bound_ variables, but not as good when the resources are _transferred_, because they're tied to the variable, not the resource itself.  
> **username_7** (2024-06-26): But then I dearly missed RAII in C# (as well as copy semantics, which may indicate I was operating under the wrong paradigm).  
---
### Answer by username_15 on 2024-06-24. Score: 3
The general notion of resources should be better thought of as a responsibility. An entity acquires a responsibility when it asks some other entity to change its behavior, to the detriment of some other entities, *until further notice*; after having issued the request, the entity that issues it has a responsibility to ensure that the appropriate notice will be given.

A memory manager may be asked "please refrain from allowing anyone else to use this memory until I say I'm done with it". A file manager may be asked "please refrain from allowing anyone else to use this file, and to the extent possible defer updating the version on disk, until I say I'm done with it". A database may be asked "please refrain from allowing anyone to access record X until I say I'm done with it.".

Instead of trying to think in low-level terms about files, memory, and so on, it's far better to recognize the high level concept of responsibility to deliver notice, since that underlies almost all "resource cleanup" patterns.

BTW, a feature that is all too often missing in RAII-style constructs is a means of distinguishing normal and abnormal circumstances for giving notice. If code which is editing a database record throws an exception, having the responsibility wrapper notify the database that the transaction has been abandoned would be useful, but if the controlled block exits without having either committed or rolled back the transaction, it would often be more useful to throw an "improperly abandoned transaction" exception. The abandonment of the transaction shouldn't cause a double-exception fault, but it should throw an exception in situations that would otherwise represent "normal" release.
---
### Answer by username_12 on 2024-06-24. Score: 0
* Forgetting to unregister an event in the C# style of event system.

But if your language has weakrefs, you automatically solve this before calling it RAII. If it doesn't, but depends on other garbage collectors, because this reference exists, the event callback target is never freed, so it can never unregister automatically. If it doesn't, and objects could be unmanaged, you may have other memory safety problems.

* Forgetting to revert changes in backtracking algorithms.

For example, in the internal implementation of regex, one should not expose information in unmatched paths. Depending on how you implement this, it may cover all side effects and extend the scope of this problem by too much.
> **Comments:**
> **username_8** (2024-06-26): I'm not sure how weakrefs solve the problem?  
> **username_9** (2024-06-26): @CoffeeTableEspresso the event only holds a weak ref to the object that registered, so the next time the event is raised after that object is collected, the event can unregister it  
> **username_13** (2024-06-26): Weakrefs generally don't solve the same problem as RAII, because with GC you usually have no guarantee of *promptness*. RAII and similar mechanisms have well-defined cleanup time, whereas an orphan weakref may linger *indefinitely* until the GC finalises it. Memory pressure is different from resource pressure, and a GC triggers only on the former. Critically, in many runtimes GC finalisation may never run if memory is not exhausted or the program shuts down.  
> **username_8** (2024-06-26): @Caleth you don't have guarantees of WHEN the clean-up code runs, which is a critical component of RAII.  
> **username_9** (2024-06-26): @CoffeeTableEspresso yeah, you can have a zombie event handler. It solves the problem of events being a resource leak. Even with RAII, you have to write the event system in such a way that an object subscribing to an event holds on to the subscription, so that it can unsubscribe on destruction, which often means everything inheriting from a base `Object` type  
> **username_8** (2024-06-26): @Caleth I disagree with you that it handles the problem. Say I'm listening on a specific port. In many cases I'd like to be able to immediately reuse that port, but I can't if it may take an arbitrary amount of time until that port is available again. RAII solves this for me, weakrefs do not.  
> **username_8** (2024-06-26): @Caleth I'm also not fully understanding your second point. I use RAII all the time, I've never had to worry about inheriting from `Object`, and it's never been particularly complicated as you seem to be making it out to be  
> **username_9** (2024-06-26): @CoffeeTableEspresso for a raii event registration, you have to hold onto *something* to deregister when you are destroyed. At scale, that is going to be "everything that listens to events derives from `Object` because `~Object()` deregisters" or "everything that listens to events is owned by a `shared_ptr`, with the event holding a `weak_ptr`" or some similar global restriction, because the alternatives are a recipe for leaks or dangling handlers  
> **username_13** (2024-06-26): @Caleth You only hold onto whatever you "registered with", be it a resource representation, an event loop, an event handler, or whatever. You *don't* hold onto everything that listens to anything. At least, in any sane programming language or resource framework. Holding onto everything is what leads to leaks!  
> **username_9** (2024-06-26): @MisterMiyagi either `event.register(this, ...args)` requires you to call `event.unregister(this)`, or it returns an object that you have to keep alive. Both of those things require somewhere to hold onto that something.  
> **username_8** (2024-06-26): @Caleth I have `EventRegisterer er{this, ...};`. The constructor registers it, the destructor unregisters it. I implement that class once, and then just use an instance of it whenever I need to register/unregister an event.  
> **username_9** (2024-06-26): @CoffeeTableEspresso yes. but that still means that `er` has to live somewhere. In a small scale project it might be fine for each class to have a data member for each event it ever listens to, but I'd prefer a `std::vector<EventRegisterer>` in some base class  
> **username_8** (2024-06-26): @Caleth yes that's the whole point of RAII. I keep `er` around so I can control exactly when it's created/destroyed  
> **username_9** (2024-06-26): @CoffeeTableEspresso and you still have the issue that there are *two* lifetimes that `er` has to be shorter than: the listener and the emitter  
> **username_13** (2024-06-26): @Caleth The event handler has to live *at least as long as* everything that is registered on it. Which is trivially done by GC. What isn’t done trivially by GC is both the listener and emitter being registered only for *as short as needed*, which can indeed be much shorter than the lifetime (which, as mentioned, can be indefinite depending on the GC strategy and situation). GC takes care of the upper bound, but RAII takes care of the lower bound.  
> **username_14** (2024-06-26): @Caleth Years ago, I was asked to debug an issue where, when the heap of a Java application was increased, the database connection pool would run out of connections. The issue was that connections were leaked on exceptions. The DB connection pool was using weak-refs to clean up leaked connections on GC. When the heap was increased, GC ran less often, resulting in the pool running out of connections.  
---
