eden/fs/docs/CodingCpp.md
Unless otherwise specified, defer to Meta C++ Coding Conventions and Meta C++ Style Guidelines.
Lightweight value parameters are passed by value. These types fit in registers.
void take(int i, float f, char* p, std::string_view sv);
Lightweight owning types (e.g. std::string, std::vector,
std::shared_ptr, folly::File, folly::Future) also fit in registers, but
cannot be cheaply copied.
Unconditional ownership transfer to callee: by value
void take_ownership(folly::File f);
Temporary borrow: by const reference
void borrow(const folly::File& f);
Conditional ownership transfer: by rvalue reference
void maybe_take_ownership(folly::File&& f);
Why? Because passing ownership by value is more general and the temporary can be constructed directly on the stack: https://xania.org/202101/cpp-by-value-args.
For large structs and classes, owning or not, pass by const reference or rvalue reference. The cost of memcpy'ing the value on the stack can be nontrivial.
Templates allow you to use perfect forwarding. Always write T&& and
std::forward<T>.
template <typename... T>
void forwarding_call(T&&... args) {
next_call(std::forward<T>(args)...);
}
Forward-declare types when possible. Reducing the header include graph has a
material effect on build times, especially when expensive headers such as
windows.h can be avoided.
When possible, define any nontrivial function (or even members, with pImpl) in the .cpp file instead of the header. Remember that anything in a header is compiled N times, once for each including source.