Heuristic42
Blog
Opengl
Meta
Rendering
2
edited
Jun 24 at 15:10
RAII++ - the powerful implication of always initializing
If you search, most definitions of RAII refer to using "**scope…
–
pknowles
created
Jun 24 at 15:01
RAII++ - the powerful implication of always initializing
If you search, most definitions of RAII refer to using "**scope…
–
pknowles
comment
Jun 15 at 11:42
Matrices
[deleted]
–
anonymous
comment
Jun 1 at 11:01
Matrices
[deleted]
–
anonymous
comment
May 18 at 22:30
Matrices
[deleted]
–
anonymous
created
Apr 10 at 12:38
test2
;</script>
–
Nia
comment
Feb 8 at 6:26
Matrices
[deleted]
–
anonymous
edited
Feb 3 at 7:54
Embedding GDB pretty printers, just like natvis
Pretty printers are awesome, but the setup can be a real pain. …
–
pknowles
created
Feb 1 at 12:27
Embedding GDB pretty printers, just like natvis
Pretty printers are awesome, but the setup can be a real pain. …
–
pknowles
comment
Jan 26 at 8:20
Matrices
[deleted]
–
anonymous
comment
Jan 15 at 7:46
Matrices
[deleted]
–
anonymous
comment
Jan 14 at 8:05
Making a real EMF Reader
All good/my bad. A half implemented feature that I really shoul…
–
pknowles
comment
Jan 14 at 8:03
Making a real EMF Reader
I don't have a circuit diagram sorry. The LEDs are all on separ…
–
pknowles
comment
Jan 10 at 0:07
Making a real EMF Reader
а есть подробные схемы что к чему подключать и куда припаивать…
–
anonymous
comment
Jan 5 at 18:00
Matrices
[deleted]
–
anonymous
comment
Dec 15 '24
Matrices
[deleted]
–
anonymous
comment
Nov 27 '24
DerBard: Custom Split Mechanical Keyboard Prototype
hello
–
anonymous
comment
Nov 20 '24
Matrices
[deleted]
–
anonymous
created
Oct 21 '24
Iterators: pointers vs cursors
You're already doing both of these by hand. This post emphaisze…
–
pknowles
comment
Oct 11 '24
Matrices
[deleted]
–
anonymous
comment
Oct 5 '24
Matrices
[deleted]
–
anonymous
comment
Oct 1 '24
Matrices
[deleted]
–
anonymous
comment
Sep 24 '24
Matrices
[deleted]
–
anonymous
…
View All
Log in
RAII++ - the powerful implication of always initializing
leave this field blank to prove your humanity
Article title
*
Article revisions must have a non-empty title
Article body
*
If you search, most definitions of RAII refer to using "**scoped objects**" and destructors to avoid leaking resources ([e.g.](https://stackoverflow.com/questions/2321511/what-is-meant-by-resource-acquisition-is-initialization-raii)). However, pulling on the literal words *Resource Acquisition Is Initialization*, yields far stronger implications. Resource acquisition (allocation or ownership transfer) happens at the same time as object initialization. They are tied together so the "resource is guaranteed to be held between when initialization finishes and finalization starts" [[wikipedia](https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization)]. What does this really give us? Sure, we don't have to remember to free resources, like memory, and they won't leak. Resource lifetimes and ownership is well defined. But.. RAII implies the **resource is always valid**. After the object is created and right up until it goes out of scope it's there. Any time you access the object you know it exists and is valid. Wouldn't that be nice if you never had to check for a null pointer or check if something succeeded so it's safe to use? You could spend time writing code for the happy path, knowing execution can't get there unless all the objects you need exist and are valid. > RAII guarantees that the resource is available to any function that may access the object [[cppreference](https://en.cppreference.com/w/cpp/language/raii.html)] I'll say it again: **code for the happy path**. Forget resources. What if we apply this to all objects? What if we start coding so that you can't create an invalid object? (TODO: examples) # How? Lets look at some of the difficulties. ## Dependencies Now, in order to fully initialize an object, all its dependencies must be fully initialized and passed to the constructor. New adopters of this idea may initially find this infuriating. At first it may just seem like a few compiler errors. Then there will appear to be cyclical dependencies that can't be resolved. You can't declare a pile of objects and initialize them later at will. At first it seems like you're just prevented from doing what you know works fine. Some people may reach for `shared_ptr`. Resist. This is a good thing. This is the compiler telling you **the design of your objects needs reworking**. How bizarre. The compiler giving errors about code design now? This extended RAII is encouraging good design.. at compile time! ## Constructor Failures What if resource aquisition fails? Exceptions. There's just no good other way. Some ideas like factory functions that return `std::expected` or `std::optional` can work, but IMO it's fighting the intent of the language. A common complaint of exceptions is performance. Ideas like [Herb Sutter's affordable RAII](https://www.youtube.com/watch?v=ARYP83yNAWk) give me hope. ## Object Composition and Returning Values Going on a bit of a tangent, RAII can be harder when objects are not movable. A stopgap can be to delete the copy and move constructors and assignment operators, then keep all your objects in a `unique_ptr`. I'd encourage instead supporting move semantics ([std::move](https://en.cppreference.com/w/cpp/utility/move.html)) and following the [rule of 3, 5, zero](https://en.cppreference.com/w/cpp/language/rule_of_three.html). Once done, you can construct an object by moving one or more into it, taking ownership of it. You can also return objects, which is often free due to *return value optimization*. ## Temporary Objects in Initializer Lists There's a couple of tricks I like to use for this: 1. Move construction out to an inline `make*()` call. This can also make the initializer list look a bit neater 2. Overload the constructor to take the temporary as an argument and call it from another with *delegating constructors* ## Edge Cases Some objects hold many other objects and the initializer list becomes giant and ugly. Yes, and yes, but right now we don't have an alternative. Use the above tricks, break up the object and eventually pick between pretty and safe code. What if you really need delayed initialization but your object has no publically accessible null state? Use `std::optional` and `.emplace()`. Ultimately the idea is to have safer and more restrictive code by default. Make your objects non-nullable unless you really need it in a specific case. Some tools such as lazy evaluation are at odds with always-valid objects. What happens if delayed construction fails? There's a new failure path and exception safety becomes important. **Don't throw the baby out with the bathwater**
Toggle Preview
Edit message
*
A description of the changes made
Discard Draft
Save Draft
leave this field blank to prove your humanity
Flag
the thing you clicked
for moderator attention.
Reason choice:
Spam, promoting, advertising without disclosure
Rude, inappropriate, generally offensive
Too arrogant or demeaning to others
Other
Reason:
The reason for raising the flag
Error