4 ms·
Right now one of the major gripes I have about Modern C++ is RAII / Rule-of-five. After going through all of this stuff I felt it brought too much complexity fo
by lasagnaphil 8y ago
Right now one of the major gripes I have about Modern C++ is RAII / Rule-of-five. After going through all of this stuff I felt it brought too much complexity for what it tried to accomplish...
RAII basically assumes that your objects are always going to be in the init-use-free pattern (you read a file, you use it, and close it after you’re finished) In reality not all things work this way, as objects have various different states according to their state machines and will use and free resources depending on that state. But in Modern C++ you’re forced to think only in the on/off paradigm, which results in lots of small unnecessary classes with their own on/off state. (If you try graphics programming you’ll understand right away...) Now when you add rule-of-five this becomes a monstrosity to handle, as you have to ensure about memory copying/moving for every little RAII class you make.
So why not let normal assignment be shallow copy by default, but have an explicit copy() method? Why is everything so implicit in Modern C++ where you can’t assure that by simply looking at a = b you can’t tell how memory is allocated/freed...
Nowadays I have lost hope in Modern C++ and are looking for alternatives: Rust (complex but at least memory safe) Orthodox C++ (not memory safe but at least sane for graphics/game programming), or Jai/Zig/other experimental lnguages (which claim to be a better C)
- colanderman 8y agoAssignment is supposed to perform a deep copy because otherwise you need to be aware of the implementation of the object you are copying, which may or may not allocate data on the heap. By forcing a deep copy, all assignments have identical semantics – you obtain a new, independent copy of the resource. You could say, "well, developers can just adopt a uniform semantics for what parts of objects are considered 'shallow' vs. 'deep'", but now the compiler can generate correct default copy operations in many fewer cases, since the rule is arbitrary vs. simply "copy everything".
- slavik81 8y agoI'm a graphics programmer myself. To be honest, my strategy for OpenGL-related resources is to allocate everything I'll ever need at program start and leak everything at program shutdown. It's simple and efficient and all copies are indeed shallow. However, if I was writing more generic code, I would probably make extensive use of movable but non-copyable containers for my OpenGL resources. You're right that the RAII model sometimes feels a bit limiting for the complexity sometimes found in graphics, but I think part of that was self-inflected by our API design. That seems to be changing. The best-looking technique I've seen for handling Vulkan/DX12 is to make your program more like a compiler. You take a scene as input and you compile it into a command buffer to give the GPU. Your resource handling for stuff like texture slots thus looks more like register allocation. State shadowing is a trivial optimization pass when your GPU code is data. The problem is that when you write RAII classes for GPU resources in the traditional way, C++ sees the GPU state through a tiny pinhole and thus can't optimize very well. When you treat your GPU commands as a program that your C++ program is building, you have more global information about GPU state available, which allows you to make more efficient choices.
- MauranKilom 8y agoModern C++ RAII is more about rule of zero than rule of five. How many different kinds of resources do you manage (that also can't be handled by std::unique_ptr with custom deleter) that you need "lots of small unnecessary" classes? If your classes manage a resource and also do something else, that's a clear violation of the rule of five/zero paradigm: When your class manages a resource, it should only do that and correctly implement all five special member functions, otherwise it should default all of them. In most cases, smart pointers can do the latter for you already. For example, it's trivial to have shallow copies by default - just wrap it in std::shared_ptr (or a thread-unsafe homebrew version if you can prove that synchronization is a performance problem). I admit to not having done a lot of graphics programming, but I can't shake the feeling that you are using modern C++ wrong if your complaint is "too many small RAII classes".