For certain kinds of large scale real-time and resource tight applications, C++ remains highly desirable to me. The key is in part being to break down large applications into some kind of smaller components, as well as to focus on both readability and debuggability of C++ product code. Clarity can be your friend and often matters when working with large scale systems.
While C++ has language features that can make breaking down large projects, it never really adapted these fully into the standard library. There are containers, which are useful for data structures and generic typing thru templating, but there are many things that have never been standardized (networking and cryptographic operations, for example) because different platforms went their own ways for these and nobody seems able to agree.
To get a model of common code, to have consistent code patterns, practices, and cross-platform functionality, I always have produced my own auxiliary library for C++ that I then re-use internally everywhere. The earliest form of this was what became GNU Common C++, which originated in the 90's. The latest iteration is moderncli, found at https://gitlab.com/tychosoft/moderncli .
For various reasons, I chose to baseline current development around C++17. I also chose to do a library of stand-alone header files only. Header only libraries have the advantage that type inference (for using auto) works much better when the entire code body is present (inline) with the header. It also eliminates lots of issues with dll's, linking of yet another library, etc. By being stand-alone, I can also shave off parts of the library and vendor it directly in other software without difficulty. In fact, moderncli began life simply as headers I had copied into other projects in the past.
Moderncli also proposes that attaching code blocks thru lambdas can be a powerful and convenient class extension model than classic C++ inheritance or templating. Some of this is influenced by my experience with Ruby, which often favored closures for wide ranging uses, including basic file processing. Of course there is a generic model for tcp and ssl streaming that is based on directly using C++ iostreaming, as well as low level socket, resolver, and network address support based on traditional BSD socket functionality.
A concept I brought in from Rust is the idea of combining a container with the locking mechanism as a single (templated) unit. This means that acquiring a lock is the only means to access the contained object while guaranteeing all access and modifications to the underlying object is automatically safe and scoped to the life of the associated guard object being used.
Other functionality I considered important to standardize for my uses include daemon service support, logging, and argument parsing. Most of the C++ code I write is some kind of system daemon, and, as a practical matter, probably would never be deployed outside of posix systems, though I do have portable implementation code.
I also have function and timer queues. To me a timer queue is a lambda bundled with arguments that may be executed periodically, and acts as a kind of "internal" cron. The function queue allows me to drive a queue of lambda functions to split a component up with, and invoke with arguments. Each function executes in order in a single thread context. This makes it possible to eliminate the need for thread locking when manipulating private objects within the component itself. This concept of component execution I have also ported to C# and Go.
Presently moderncli is on track for a 1.0 release, perhaps early next year. I believe it is now likely "header" complete, if some of the header functionality for things like x509 certificates remains sparse. It is hard to determine what the future of C++ may yet become, but that seems a more distant 2.0 problem.
Top comments (0)