In our discussions about what C++ style to adopt for our codebase, and which aspects of the language and standard library to adopt and which to stay away from, Richard made the excellent point that it would be worth looking at some other open source C++ projects. So I’m making this thread to collect examples of C++ projects that appear to be worth examining, and as a place for any discussion. When this came up, we were discussing use of
std::move, so I will call those out in particular, but I don’t want to restrict this thread to those specifically.
Here’s a few to start:
http://seastar.io/ — “Seastar is an advanced, open-source C++ framework for high-performance server applications on modern hardware. Seastar is used in Scylla, a high-performance NoSQL database compatible with Apache Cassandra. Applications using Seastar can run on Linux or OSv.”
I’m a little disappointed I hadn’t looked at this before. From a first cursory glance, they appear to be in a very similar problem space as we are.
In their docs here, under the section “Lifetime Management”, they discuss making use of
std::move, and both
std::unique_ptrand their own single-threaded implementation of
seastar::shared_ptr. A search in github shows significant use of
unique_ptr. I will definitely need to look through their codebase more to see if there is anything worth discussing with the team.
http://www.includeos.org/ — “IncludeOS allows you to run your application in the cloud without an operating system. IncludeOS adds operating system functionality to your application allowing you to create performant, secure and resource efficient virtual machines. IncludeOS applications boot in tens of milliseconds and require only a few megabytes of disk and memory.”
In terms of C++ style, they say they follow the C++ Core Guidelines pretty strictly, which are very clear about their suggested usage of smart pointers for resource management and ownership control. A search in github shows heavy usage of
unique_ptr, where many of the search results are type aliases like
class Request; using Request_ptr = std::unique_ptr<Request>; class Response; using Response_ptr = std::unique_ptr<Response>; class Server; using Server_ptr = std::unique_ptr<Server>;
Every object has an “owner”. The owner may be another object, or it may be a stack frame (which is in turn owned by its parent stack frame, and so on up to the top frame, which is owned by the thread, which itself is an object which is owned by something).
The owner decides when to destroy an object. If the owner itself is destroyed, everything it owns must be transitively destroyed. This should be accomplished through RAII style.
The owner specifies the lifetime of the object and how the object may be accessed. This specification may be through documented convention or actually enforced through the type system; the latter is preferred when possible.
An object can never own itself, including transitively.
When declaring a pointer to an object which is owned by the scope, always use kj::Own. Regular C++ pointers and references always point to objects that are not owned.
Abseil — Google’s open source C++ library. The lead of Google’s C++ libraries group, Titus Winters, is also the chair of the Library Evolutions group for the C++ standards committee, so it’s not surprising that they are strong advocates of the “modern” resource management style. Titus is also the lead of C++ education in Google, and with the open source release of Abseil he has started publicly publishing some of the “Tip of the Week” C++ articles they have written. The article TotW55 is a nice explanation of usage of unique_ptr different from others I’ve seen. Unique_ptr is the subject of several articles: TotW123, TotW126, TotW134. TotW77 is a nice way of thinking about move semantics continuing from TotW55.