I understand C++ as well, or better, than most (or all) of my peers, and certainly betters than people on here thinking they need to explain to me how RAII works. Do you want to argue that C++ RAII / objects stuff isn't complex and doesn't put considerably restrictions on how you design your app, then maybe you should reconsider.
I would argue that if cleaning up resources properly is among the hard problems, or among the most error-prone problems in your code, then maybe you're problems aren't that hard or complex after all.
I'm currently working on a distributed caching system and on real time voxel geometry boolean operations simulation (on GPU), both on the scale of >= 10^9. Is that "complex" enough? Both are done in C++. C++ helps exactly 0 in achieving any of these things (as opposed to using plain C), well the one help is I don't have to type 'struct' all the time.
In fact, in one of these projects I was pushed to use STL initially. I'm now working on getting rid of the last of them because we have had concurrency bugs and performance problems from using them. The code was not obvious and using STL containers (std::deque is very bad specifically) meant the actual runtime characteristics depend on which STL implementation is being compiled in. It would have been easier to just do straightforward obvious manual code.
You don't understand even the first things of what I say. That's because you apply beginner level concepts and understand to argue, and are not looking for nuance or deeper understanding at all.
You don't get it. That's because you still don't understand some basic things about the language. There is no method call here on a pointer expression. There is only a call on a value expression.
Well, the best way to prevent mistakes is to make everything super complicated and damn hard to do. The best way to prevent mistakes is to approach it to do the essential stuff and avoid the fluffy stuff.
How about you do the following two Google (or AI) searches
"Please give me examples of great systems software written in plain C or C style procedural C++"
"Please give me examples of great systems software written in modern C++, as opposed to procedural C style C++ or plain C".
Why does it seem like the majority of core infrastructure, like Linux kernel (also vast parts of Windows/Mac OS), PostgresQL, Sqlite3, Git, OpenSSH, GCC, but also e.g. MS Office/Excel, are written in plain procedural code and not in modern C++? For the latter, I get stuff like "ScyllaDB NoSQL database" or "Envoy Proxy" or whatever, what is that even and why should I care or how do I know they're actually technically solid products and not just hype?
My claim: The arguments that I've given (but you keep insisting I didn't give them) play a huge rule in why that is so. You can use C++ RAII for plumbing and high-level stuff. But if you try to actually implement technically interesting things, it won't help you at all, it's just getting in the way.
> I don't think you did, I think you just said it has downsides over and over.
Show evidence of your claim.
> Don't ask for basic knowledge then get upset when you get it.
Where did I ask for basic knowledge? You are hallucinating. I've repeatedly and explicitly told you to shut up explaining beginner things. You are trying to refute my criticisms of RAII with your silly explanations of how RAII works. That's not how an argument or "evidence" works.
> Exceptions aren't uncontrolled flow and you can also not use them.
I would rather call it _implicit_ flow but they also lead to losing control over control flow because of that. Yes, I can just not use exceptions, and also avoid gotos and use them in a principle way, and do cleanup in a principled way. And then I can also do without RAII and without all the baggage I'd have to buy into in order to use it.
> You don't have an explanation of why the burden of proof is on me.
Please p* off man. You're being ridiculous.
> It means memory leaks and crashes which everyone has been fighting for 50 years.
Like you have been on your Linux, Windows, or Mac machine? Maybe you are running a linux machine with an uptime of weeks, months, or even years?
> Someone running a marathon without shoes doesn't mean shoes are bad.
You claiming to run a marathon with a 25kg backpack doesn't mean you don't lie, and it also doesn't prove running without it isn't the better approach.
> Why can't you give a single basic explanation instead of making the same claim over and over?
The only person not giving explanation beyond basic boring introductory C++ RAII school, that's YOU my friend. I've been giving a lot of explanations what I think is problematic, somehow it seems you're mentally unable to acknowledge them.
Pretty much all the C++ features I've used are good enough to write some toy code snippet, but it's hard to use them to good effect at scale without causing massive problems.
Even classes are an instance of this, they were to solve some perceived problems, but they created much bigger issues, such as readability issues and introducing many more compile time dependencies.
PIMPL wasn't even a C++ feature but an idiom pushed by some people. It is next to unusable because you have to duplicate the API and write all the call forwards.
One problem with std::unique_ptr for example is that there is no ergonomic way to use it to hide implementations. The reason is it relies on destructors and to use destructors the class definition needs to be visible.
Well that's a lie. I've long been back to raw pointers and it's by far the easiest way to do it. All of Pimpl, unique_ptr, and whatever other clever mechanism (I'm not even looking at std::indirect anymore) just aren't really ergonomic.
Nobody needs "deep copying", ever. It's not even well defined what it should mean (i.e. how deep etc.). It's purely a theoretical problem with no good practical (one-fits-all) solution. The only practical way is to copy what you need copied, when you need it. Done.
> It's your claim that destructors are harmful so the burden of proof is on you.
I have given a variety of arguments why I think the C++ RAII specifically has downsides. You can accept them or ignore them, but don't act like I didn't give arguments.
> People use them because by default values have scope based lifetimes and destructors unify the handling of stack based values which require no explicit cleanup with data structures that heap allocate,
Once again you're explaining beginner C++ do me. Are you still doubting if I understand this argument? My response to this was and is, if you have primarily stack scoped lifetimes, you are writing beginner programs. This is scripting and plumbing. It's not interesting to me. Systems programming is not so much about stack scoped lifetimes.
RAII systematicing object lifetimes and cleanup, thus enabling exceptions and implicit or uncontrolled control flow, may sound nice on paper, but turns out we shouldn't want them in the first place. What RAII leaves for me is a system that will automatically call nested object's destructors when I delete something. It's not something I want in general, I think it has more downsides than upsides for the code I'm writing. I've actually tried to use RAII many times and I've concluded it doesn't work for me.
> This is exaggerated when there are multiple returns, gotos, macros and other sources of branching especially for error handling.
If I were you, my response would be: The burden of proof is on you, show the evidence. But my answer is, yes that is right, but everything is a tradeoff, and the issues caused by manual cleanup are also somewhat exaggerated by C++ people, and the issues caused by blindly buying into the corset of C++ types are not well understood by C++ zealots (I've done my best at explaining them).
Issues caused by C approach are also a matter of design and approach to programming in general. It also depends on the actual problem you're solving. The linux kernel for example doesn't exactly have the easiest or most beautiful code to follow, but surely it's one of the most technical codebases out there, one that solves difficult problems (performant resource multiplexing for programs that it doesn't even know). On the other hand, the debugger code base I've referenced doesn't have any gotos for example, nor even early returns (or almost none, not sure).
Find me a single example of programs that run as fast and are as productively maintained as these two codebases in their respective areas? I believe there aren't any.
This should be plenty evidence to a reasonable mind, but that isn't you.
You keep "asking" for evidence but the only evidence presented by yourself is that you have merely surface-level understanding of the subject matter, and are looking for arguments, not insight and critical examination.
I asked you what's wrong with pool destructor function pointers. You gave a reason what's wrong and I refuted it. So no, I'm not saying that storing a function pointer is special, just that nothing's wrong with it. (And implying that since there's nothing wrong and it's probably the most straightforward thing to do, it's also probably the right thing).
Adding that with a principled approach, I don't even see much of an issue with doing manual creates and deletes in a object-graph type app, with many unstructured lifetimes. Sometimes that might just be required, and then the complexity is just there either way. Having to cleanups manually or not doesn't change anything about that. It's a bit more cumbersome to get everything right when doing it manually -- sure.
The problem is mostly people graduating from school thinking that somehow there is only stack and heap, and malloc/free is how you do heap. That view completely ignores that the essence of programming systems is mostly to understand the machine, and then doing conceptual and architectural work on a solution (and also on a problem). The act of writing actual code is then mostly just translating those concepts into the digital world verbatim.
Of course they are. The pointers to the vtable are part of the object. They aren't mutable fields as per the language, but for security concerns it doesn't matter what the language thinks. Being part of the object, the vtable pointer has to live in a writeable memory mapping (like stack / heap).
1. No, you're not writing code you don't have to. It's not different to implementing this as non-virtual methods, in fact I'd argue doing simple functions is more straightforward.
2. And the code being compiled is abstract & generic, it won't be instantiated for every type and bloat the executable or instruction cache.
3. Security concerns: With C++ virtual methods every object carries a mutable pointer too (to a vtable containing function pointers). What resource management side effects please?
To be fair, Odin _had_ a Wikipedia page and it has been removed because of... people with whatever interests. But I'm still agreeing with your general point. I use C/C++ because it seems to be the least friction option to me overall, and I don't want to deal with language but simply focus on my actual compute problem. (Given that, I spend an unreasonable amount of time in silly fights about language).
I've argued elsewhere some things that are wrong with RAII and C++ objects in general.
Here I would just like to mention that if you have to rely on "de-virtualization" passes, you're in a miserable situation architecturally. If you have code where the overhead of virtual function calls might be too much to pay, don't do virtual functions then. End of story.
To deconstruct a pool of objects, I don't see what should ever be wrong with a function pointer. The overhead of loading the function pointer will get divided by the number of objects being deconstructed. Care to explain what's the issue here?
Designing something good for me means going through at least 11 seriously bad approaches before half understanding the problem and having a half-working solution. Trying to use a notebook to aid a learning or research process at all has always meant wasting a lot of time "perfecting" those bad approaches. And ending up with lots of notes that document nothing but a painful struggle to make sense. Looking back through the notes that I did take, in notebooks that I have been gifted over the years, is almost unbearable. The approaches I tried before arriving at the right one were fundamentally wrong, there is no fixing them, and it's painfully obvious when looking back. Aside from the emotional problems I perceive there, it's obvious to me that there is no engineering value in keeping those notes at all.
The current best design always lives in my head, and by the time it exists, the solution and understanding is so clear and detailed that I can't be arsed to write it down.
I do think there is value in taking notes for others, though.
What works a little bit for me is having a lose stack of papers at work. The topmost paper serves to put a coffee mug on top, that will take the coffee stains so the table stays clean. From time to time I actually scribble something on a sheet, and since the sheets are all loose it's very easy to discard any sheet after it's served its (diminishingly small) purpose as a thinking aid.
> Also one separate function being different than the operator is not a language level feature, it is how that one library data structure is made.
That's not so much the point: the point is that even when calling a regular method conveniently as ptr->methodname(), you are calling the method name not on a pointer expression but on a value expression. ptr->methodname() is effectively (*ptr).methodname().
> Again you can make these bold statements but saying pointer chasing has no performance impact is what people say when they don't understand the cost of TLB misses and caches misses.
You are right to call this out but I did not mean to imply that it would not increase load on the cache at all. The most important optimization is keeping data structures simple, flat, and coherent. Making many micro optimizations can backfire because it reduces clarity and flexibility. I should not argue that vector metadata block should not be embedded as value in a struct, but move semantics is where it is getting silly, complicated, and we are losing control of program behaviour.
For example, with your cache concerns, don't forget to group data by access patterns and write patterns. Not doing so may hurt the cache more than an indirection. If you blindly embed everything by value religiously, you deserve neither flexibility nor correctness nor performance.
> Yes you can, an operator is just a function, get it?
An operator is just a function but with different syntax. You can not do my example, that snippet does not do the intended job. Get it?
> (unless you want to try to say that not defining your structs is a good idea).
It is a good idea when it's about architecture. It is right to embed small and in particular stateless structs directly, but otherwise adding one level of indirection is often absolutely the right call.
> All I was arguing was that destructors are good
All I'm saying is that destructors, while they may seem convenient, are way overrated and the systemic issues caused by reliance on C++ classes and class features (including destructors) are still not well enough understood by the mainstream in 2026.