3 ms·
> RAII doesn't work without bringing in a whole lot of other heavy-duty features: mainly exceptions, but also constructors and destructors. You don't need exce
by jcranmer 4y ago
> RAII doesn't work without bringing in a whole lot of other heavy-duty features: mainly exceptions, but also constructors and destructors.
You don't need exceptions to make RAII work. It does make fallible resource allocation a little bit trickier (the RAII object needs to be prepared to be in a live-but-failed-allocation state), but it's very doable. Constructors and destructors are absolutely not heavy-duty features.
- tsimionescu 4y agoThey are heavy duty precisely because they rely on exceptions to signal error conditions (or, in the case of destructors, are completely unable to signal errors safely at all), at least in combination with RAII. Without exceptions, RAII is quite cumbersome - especially in kernel mode, where you can't assume that memory allocation is always successful, so even memory allocation is a fallible resource allocation. Not to mention, RAII makes it impossible to check whether you successfully released the resource, which is a concern that the kernel can't always ignore the way user-space C++ code usually can.
- fluoridation 4y agoThe key to RAII is not so much constructors as destructors. If you want to be able to signal construction failure you just have an init() member function that returns a bool or some integer. As for dynamic allocation, when I worked on driver development for Windows, I just had an allocate<T>() function that returned a properly constructed std::unique_ptr<T> with the deallocation function properly set and with the T fully constructed (you may need more than one allocation function if you need to allocate from multiple contexts that require allocation in slightly different ways). >Not to mention, RAII makes it impossible to check whether you successfully released the resource Actually, RAII makes it much easier by encoding that knowledge into the owning object. Using the example above, you could call allocate<T, do_something_special_on_deallocation_failure>(). Then whenever the pointer goes out of scope you'll do the special thing without the user of the object having to know what that special thing is.
- tsimionescu 4y agoAll of this complicates the program significantly, and greatly reduces the advantages of RAII. If you're not using the constructors for initialization, than your desturctors also have to handle the case where the objects didn't even attempt to acquire the resource they may represent, for example. Also, how to handle a failure to release a resource is context dependent, you can't encode it in the type of the resource unless you create a different type for each call site.
- fluoridation 4y agoIf you really need to do something different at each release point then you can have do_something_special_on_deallocation_failure() notify the error to the release point by a number of different mechanisms. Yes, all of this makes the code more complicated. The point of these features is not to make the code simpler, but to make it more robust. Rust is also more complicated than C.
- germandiago 4y agoYes, without exceptions is more involved, but way easier than any C alternative doing couple-of-functions mstching for alloc/dealloc.
- jcranmer 4y agoIf you're relying on exceptions to make destructors fallible, you are going to have a very bad time. The protocol of throwing an exception is to destroy all objects in scope, and if doing so causes more exceptions to need to be thrown, you're going to end up either with a hard crash or one of the exceptions being destroyed. If the fallibility of resource deallocation is really important, then RAII isn't a good model to use (I prefer something like a connection.with_transaction([](Transaction &T) -> Result) model myself for this). Given that fallible destructors aren't an issue, exceptions are only an issue for RAII if constructors can only fail with exceptions. Note that Rust has fallible constructors without exceptions, and C++ could implement that too, though it is definitely less ergonomic than exceptions.
- usefulcat 4y ago> Not to mention, RAII makes it impossible to check whether you successfully released the resource, which is a concern that the kernel can't always ignore Serious question: what does the kernel do if it fails to release a resource? Like memory, for example?