▲ | rerdavies 7 months ago | |
As an old-timer, I think you have some serious misconception about how RAII works, and what it does for you. > Arena management There's nothing that stops you from using arena allocators in C++. (See pmr allocators in C++17 for handling complex non-POD types). > The cost of RAII_ you're going to have to clean up one way or another. RAII can be zero-overhead, and usually generates less code than the C idiom of "goto Cleanup". > Use of destructors leads toward template APIs. Not getting that. Use of destructors leads to use of destructors. Not much else. > If you don't use exceptions.... Why on earth would you not use exceptions? Proper error handling in C is a complete nightmare. But even if you don't, lifetime management is a huge problem in C. Not at all trivial to clean things up when you're done. Debugging memory leaks in C code was always a nightmare. The only thing worse was debugging wild memory writes. C++ RAII: very difficult to leak things (impossible, if you're doing it right, which isn't hard), and if it ever does happen almost always related to using C apis that should have been properly wrapped with RAII in the first place. Granted, wrapping C handles in RAII was a bit tedious in C++89; but C++17 now allows you to write a really tidy AutoClose template for doing RAII close/free of C library pointers now. Not in the standard library, but really easy to roll your own:
> C++ 20 undefined behavior of a read-after-free problem.That's not UB; that's a serious bug. And C's behavior would also be "UB" if you read after freeing a pointer. | ||
▲ | charleslmunger 7 months ago | parent | next [-] | |
>As an old-timer, I think you have some serious misconception about how RAII works, and what it does for you. I appreciate the education :-) >There's nothing that stops you from using arena allocators in C++. This is true, but arenas have two wonderful properties - if your only disposable resource is memory, you don't need to implement disposal at all; and you can free large numbers of individual allocations in constant time for immediate reuse. RAII doesn't help for either of these cases, right? >Use of destructors leads to use of destructors I guess what I mean is... It's totally possible and common to have a zillion copies of std::vector in your binary, even though the basic functionality for trivially copyable trivially destructible types is identical and could be serviced from the same implementation, parameterized only on size and alignment. Destruction could be handled with a function pointer. But part of the reason templates are used so heavily seems to be that there's an expectation that libraries should handle types with destructors as the common case. >lifetime management is a huge problem in C. Not at all trivial to clean things up when you're done. Absolutely true if you're linking pairs of many malloc and free calls. But if you have a model where a per-frame or per-request or per-operation arena is used for all allocations with the same lifetime, you don't have this problem. >And C's behavior would also be "UB" if you read after freeing a pointer. The specific issue I ran into was the destructor of one thread_local reading the value of another thread_local. In C++17 the way to do this was to make one of them trivially destructible, as storage for thread locals is released after all code on that thread has finished, and the lifetime for trivially destructible types ends when storage is freed. In C++20 this was changed, such that the lifetime of a thread local ends when destroyed (rather than when storage is freed) if it's trivially destructible. C thread local lifetimes are tied to storage only and don't have this problem. | ||
▲ | badmintonbaseba 7 months ago | parent | prev [-] | |
You can use `unique_ptr` with a custom deleter for wrapping C libraries.
The lambda in decltype is C++20, otherwise the deleter type could be declared out-of-line. |