Unique_ptrs are a total game changer, and the ability to use closures and lambdas when you want to set a callback function instead of a function pointer with a context pointer you have to cast and decode is absolutely huge for readability. maybe we aren't getting every last bit of performance out of it that we could with C, but it works at our pretty ridiculous scale, so I think C might have been a premature optimization for us.
And layers upon layers of object oriented crap is also a problem in C (I've seen it). At the end of the day I've just been burned more by the complexities of building large things in C (particularly when people do reference counting in C) than I have been by the complexity of c++ in general.
You meant that a linear type system is a total game changes. Unique_ptrs are an ugly hack to emulate a linear type system in an inadequate language.
Why build your own when C++ has std::shared_ptr.
C doesn't have a destructor that gets called when something goes out of scope. That's taken advantage of in C++ (RAII) to implement various things (like scoped_ptr that helps avoid leaks).
Refcounting is also not perfect for every case.
But I like and prefer C. ;) Just pointing out one thing different in C++.
I've worked on C++ apps that had built-in garbage collection (basically asset (geometry) paging) for huge amounts of data that would allocate/free/page on demand based on what was going on.
> String manipulation in C is a tedious chore.
Use a dynamic strings library, like Postfix for instance, and everything else.
> C lacks good memory management.
So strange that you went for C++ for most of your code that is not immune of problems from this point of view. I could understand that point if you were opting for a language with GC support. With C you can easily get better (that is, safer) than C++ native MM just building a reference counting system on top of your C "objects". This is trivial and it is what Redis, Tcl, C-Python, and many others are doing.
With Redis memory leaks or memory management never was a big issue.
> Error handling is optional and cumbersome.
Exceptions mostly suck, and in system software the only sane way to deal with errors is C-alike IMHO, that is, check the return value / error returned by every function and act accordingly.
> Encapsulation and other object-oriented features must be emulated.
This is not an objective point since many thing that this features are actually a problem.
Weak points IMHO, and C++ and Python with the minority of Python looks like a design error.