> Funny that you mention the decoupling of state and logic, because I see that as a non-issue in C.
I beg to differ. Decoupling logic and raw data is not an issue in C, but state is not the same as raw data. You may have the same state data duplicated in memory (e.g. an index), and there's also the issue of representation of state which is not portable (e.g. pointers, particular data structure). You also have pointers to functions (logic) in your data if I understood you right.
With C++ (or any sufficiently high level language) you can easily abstract away the difference between state and raw data. If you've got function pointers or pointers to instances of logic objects (which is a must if you don't want to litter your code with long switch clauses), you could save them as type IDs or something akin to that.
You might be programming something very different, but so far most good C code I've seen was thoroughly objected-oriented. Not in the sense it religiously followed the 3 pillars of OOP, but in the sense it coupled structs with several functions that have been meant to use on solely with these structs and sometimes employed polymorphism by embedding function pointers in these structs.
All of that is much easier to do with C++ classes, and if this is all you wanted (and you don't think you need proper separation of data from bone fide state), you can have a code that would refresh the vtable pointer in memory, and would sure be more straightforward than manually updating function pointers all over the place.
> It currently lacks safety and proper compression, so if I get serious about it I'll probably make all network data go through validation functions, which helps with both compression and handling hostile data.
Validation is nice, but you can't foresee every weird way your data could be shaped. It's very easy to miss one small corner. That's why you see several security engineers going around these threads dissing C. :)