9 ms·
> theoretically RAII is about general resource management, not just about memory. But at least in my experience, it’s always about memory management only if y
by zabzonk 4y ago
> theoretically RAII is about general resource management, not just about memory. But at least in my experience, it’s always about memory management
only if you ignore things like iostreams, thread locks, etc.
- TillE 4y agoYeah, RAII helps you manage any type of OS handle with minimal effort. I can grab a mutex with std::unique_lock and not have to worry about releasing it manually, which means simpler code and fewer bugs.
- jstimpfle 4y agoThis is a mostly theoretical argument in my experience. It's quite easy to close the things that you need to close (if there are very many, something is wrong). RAII can improve "scripting" speed when putting a lot of automatic variables on the stack. However, a lot of those variables need to be moved to the heap when proofing out the code, and that consolidation isn't going well because RAII doesn't work with generic code (void-pointers, memcpy etc). You need to go all-in with RAII containers. Which causes a lot of boilerplate and increases compilation times.
- moloch-hai 4y agoYou appear to be using "generic" to mean "C-ish". That is not what the word means, in context, and there is no reason to do any of it anyway. "Proofing the code"? Does that mean anything at all? For RAII on heap objects, you have std::unique_ptr, and no boilerplate. Anyone failing to lean into RAII to manage resources is just choosing to write unreliable code. Or C, but I repeat myself.
- mgaunard 4y agoDue to language limitations, a lot of C programmers make all their variables shared pointers, which means they don't have to figure out how to do value semantics, moving and copying objects, especially in multithreaded environments. Interestingly, it seems Rust programmers do the same too, because otherwise programming in Rust is too hard.
- jstimpfle 4y ago> Due to language limitations, a lot of C programmers make all their variables shared pointers, which means they don't have to figure out how to do value semantics, I wouldn't approve. Make shared (i.e. ref-counted) pointers when actually needed. Writing C is best when not mimicking bigger languages (i.e. with GC), but when figuring out how a system can work optimally.
- mgaunard 4y agoYou might not approve, but the reality is that most C code is built like that.
- secondcoming 4y agoI assume you mean C++ here? In any case, in my experience this bad practice comes from Java devs who’ve moved to C++.
- moloch-hai 4y agoJava Disease is its own topic. But most shared pointer ownership in C is wholly ad hoc, without even reference counting.
- mgaunard 4y agoNo, I mean C. People don't do that in C++, since C++ provides ways to define value semantics (copy, move, assignment).
- tialaramex 4y agoYour theory is that Rust programmers "make all their variables shared pointers" ? Even if I generously assume you're thinking of C++ "shared pointers", and so you've concluded that Rust's Rc<T> (a reference counted T) is basically the same thing, I don't see where you'd come to the conclusion that Rust programmers do this for "all their variables" as this seems wildly unlikely.
- 4y ago
- jstimpfle 4y ago> "Proofing the code"? Does that mean anything at all? Since you're already schooling me on the meaning of terms, you probably have enough experience to have realized that the typical code begins life in a stubbed out form that is barely functional enough to deliver first results. It is then iteratively enhanced and made more widely applicable, more robust, more refined, better specified, more performant, and so on. In the process, the code is undergoing many revisions, and moving data structures from automatic storage (stack) to the heap is very typical. Another word I'm thinking of for this process is "consolidation", which I have also used. My apologies if I don't speak in your terms / in the most precise terms.
- moloch-hai 4y agoI don't have experience of this "moving from ... stack to the heap", in C++. Correct code is the same wherever the objects live, whether stack, member, or heap. Changing it costs time and adds faults. This proofing process is another example of what makes coding C more costly and buggy than coding C++. I did it for years, and miss it not at all.
- jstimpfle 4y agoIf writing systems-level code solving for non-trivial requirements, the majority of the state has a lifetime that outlives any particular function call. That's when you need to move that state to the heap. There's no clear scope anymore, ownership has to be moved from function scopes to RAII managed container structures. Things are quickly getting more complicated and expensive (software complexity/bloat, compile times, binary size...) when you have to nest your structures in templated containers that don't know what you're nesting in them... This is where all the complexity with 17 constructor types and 99 move semantics with const, non-const, r-valued references and abstract virtual base classes came from, and there might be less than a dozen persons left on the planet who really understand it all...
- moloch-hai 4y agoWith RAII, it is trivial to move things from stack to heap, or to a member of something that might be on the stack or heap or in a container, without changing any of the code that implements the object. Most usually you don't need to declare or define any constructors, assignment operators, or a destructor; the compiler provides them, and guarantees they are correct. (Sometimes you provide one constructor as a convenience for users.) It has been many years since I found a use for an abstract virtual base class. Literally millions of people understand it all, and use it every day with no difficulty. You don't need to invent difficulties, or waste days "proofing" code that may be written exactly once and never touched again.
- EliRivers 4y ago"It's quite easy to close the things that you need to close" Very true. It is easy. Not difficult. That doesn't seem to stop enormous amounts of C++ code being created in which this is simply got wrong. Just because it's easy doesn't mean that huge numbers of programmers won't still get it wrong. They do. Regularly. If they adopt RAII conventions, they screw it up far less frequently. Those are the facts.
- jstimpfle 4y agoI prefer reducing complexity instead of hiding it in language cleverness. (Because hiding complexity doesn't make it go away). Try adopting ZII (Zero is initialization) and context managers (pooling, chunking, freeing in batches etc.), this can reduce the amount of boilerplate to a minimum. Writing generic code like that (down to the binary level) also helps improving many other metrics like executable size etc.
- EliRivers 4y agoThat's nice, and I'm sure your code is just lovely, but there's just one of you and millions of people writing C++ who can't do that but can just about manage some simple RAII.
- kllrnohj 4y ago> Because hiding complexity doesn't make it go away). Try adopting [..] context managers (pooling, chunking, freeing in batches etc.), this can reduce the amount of boilerplate to a minimum "don't hide complexity in small, single-purpose, composable containers, instead hide complexity in hulking behemoths which can consume months of refactorings & iterations" ? That's not simplifying your code to be generic. That's adopting a particular framework & coding style. Which yes, you have to do in C, but you're doing that because of language issues. You're not saving yourself from "language cleverness"
- moloch-hai 4y agoYeah, stopped reading after that. How wrong does he want to be? It is hard to tell what the point is of this article is. Yes, the C-ish subset of C++ differs from ISO C, in trivial details. That is irrelevant to C++ users, who may consult ISO C++ to discover the actual subset. They interact with any C only when they #include a header for a 3rd party C library, and then the relevant subset is what, exactly, appears in that header. There is really no legitimate reason to code C anymore: A C++ compiler is available for any modern development target. Confining yourself to any C subset (with or without ISO C marginalia) amounts to crawling when you can fly. To be more specific: nothing that can be done using C is unavailable to the C++ coder, but enormous power is available to the C++ coder and wholly unavailable in C.
- jstimpfle 4y agoFor me the legitimate reason to code C is to get stuff done, period. There is hardly a need for more (to do what I do -- systems in the broadest sense) and there's a lot of time saved by not thinking about 21 "safe" and "ergonomic" ways to write everything in C++ (that very often end up being not that safe, and unintelligible). Yes, there is the "subset" argument, only use what you need. But I don't buy that, I'm not like that, it doesn't work for me. Constraining myself makes things easier.
- glowingly 4y agoThis somewhat mirrors my own development. I started in C, and am still in it for systems/OS development at work. In UI development, we had older C toolkits, but are replacing them with newer toolkits that are C++. I started off trying to just do C business logic with some C++ glue code for the UI. Sticking to what's familiar. In the end, it was just easier to do everything properly. All C in areas that are C. All C++ in areas that are C++. Same with C#. Trying to mix them is just more work than necessary. At least I get to add C++ to my resume. There is a little joke at work, w.r.t. our existing codebases and code choices. They are career-driven choices, not technical choices. The result is a mess of a codebase, but I'm fully embracing that now.
- RcouF1uZ4gsC 4y ago
- wayne 4y agoWhile not trivial, the problem of remembering to free everything is slightly simpler when you don't have to worry about exceptions.
- pjmlp 4y agosetjmp/longjump/signals
- otabdeveloper4 4y agoYes, just put a "if (errno) goto err" after every function call in your program. (That was sarcasm, FYI. Obviously it's 2023 and nobody wants to do manual function calling boilerplate as if you're programming 1960's assembly.)
- mypalmike 4y ago*for some definition of nobody
- WalterBright 4y agoI used to do `if (errno) goto err;` a lot. I eventually realized that nested functions did the job much nicer: void err() { printf("oops, we failed"); } ... if (errno) return err(); This cleaned up a lot of my code. (The optimizer would of course inline the function, and the common tail merging would automatically convert it to the goto version in the optimizer. So this was cost-free.) Why C doesn't officially have nested functions is, well, that's C!
- mhh__ 4y agoThis is my one of my favourite patterns with nested functions - clean code, and avoid a ratsnest of 70s basic style GOTO. It starts with one goto, then one more, then another. The first goto is usually clever but then someone else arrives and hacks another one because they don't want to change the code too much.
- 4y ago
- cjfd 4y agoOne can do lots of things with RAII. I once wrote some classes to generate xml. I used constructors to write opening tags and destructors to write the corresponding closing tags....
- _dhruva 4y agoWe implemented a full blown profiler for win32 platform using RAII to track profiling data back in ~2000 https://bitbucket.org/dhruva/cramp https://bitbucket.org/dhruva/cramp