C++14 language and library features are allowed in the Open Screen Library according to the C++14 use in Chromium guidelines.
In general Open Screen follows You Aren't Gonna Need It principles.
Blink style is not allowed anywhere in the Open Screen Library.
C++17-only features are currently not allowed in the Open Screen Library.
GCC does not support designated initializers for non-trivial types. This means that the
.member = value struct initialization syntax is not supported unless all struct members are primitive types or structs of primitive types (i.e. no unions, complex constructors, etc.).
std::functionobjects are allowed.
<chrono>is allowed and encouraged for representation of time.
<mutex>are allowed, but discouraged from general use as the library only needs to handle threading in very specific places; see threading.md.
using FooId = std::stringin foo.h.
Use the following guidelines when deciding on copy and move semantics for objects:
Classes should prefer member initialization for POD members (as opposed to value initialization in the constructor). Every POD member must be initialized by every constructor, of course, to prevent (https://en.cppreference.com/w/cpp/language/default_initialization)[default initialization] from setting them to indeterminate values.
Classes should follow the rule of three/five/zero.
This means that if they implement a destructor or any of the copy or move operators, then all five (destructor, copy & move constructors, copy & move assignment operators) should be defined or marked as
deleted as appropriate. Finally, polymorphic base classes with virtual destructors should
default all constructors, destructors, and assignment operators.
Note that operator definitions belong in the source (
.cc) file, including
default, with the exception of
delete, because it is not a definition, rather a declaration that there is no definition, and thus belongs in the header (
In most cases, pass by value is preferred as it is simpler and more flexible. If the object being passed is move-only, then no extra copies will be made. If it is not, be aware this may result in unintended copies.
To guarantee that ownership is transferred, pass by rvalue reference for objects with move operators. Often this means adding an overload that takes a const reference as well.
Pass ownership via
std::unique_ptr<> for non-movable objects.
We prefer to use
noexcept on move constructors. Although exceptions are not allowed, this declaration enables STL optimizations.
TODO(https://issuetracker.google.com/issues/160731444): Enforce this
Additionally, GCC requires that any type using a defaulted
noexcept move constructor/operator= has a
noexcept copy or move constructor/operator= for all of its members.
Template programming should be not be used to write generic algorithms or classes when there is no application of the code to more than one type. When similar code applies to multiple types, use templates sparingly and on a case-by-case basis.
Follow Google’s testing best practices for C++. Design classes in such a way that testing the public API is sufficient. Strive to follow this guidance, trading off with the amount of public API surfaces needed and long-term maintainability.
OSP_DCHECK(TaskRunner::IsRunningOnTaskRunner())to catch thread safety problems early.
One of the trickier parts of the Open Screen Library is using time and clock functionality provided by
std::chronotypes in implementation code,
util/chrono_helpers.hcan be included for access to type aliases for common
std::chronotypes, so they can just be referred to as
milliseconds, etc. This header also includes helpful conversion functions, such as
util/chrono_helpers.hcan only be used in library-internal code, and this is enforced by DEPS.
Clock::durationis defined currently as
std::chrono::microseconds, and thus is generally not suitable as a time type (developers generally think in milliseconds). Prefer casting from explicit time types using
Clock::to_duration(seconds(2))instead of using
These are provided in
platform/api/logging.h and act as run-time assertions (i.e., they test an expression, and crash the program if it evaluates as false). They are not only useful in determining correctness, but also serve as inline documentation of the assumptions being made in the code. They should be used in cases where they would fail only due to current or future coding errors.
These should not be used to sanitize non-const data, or data otherwise derived from external inputs. Instead, one should code proper error-checking and handling for such things.
OSP_CHECKs are “turned on” for all build types. However, OSP_DCHECKs are only “turned on” in Debug builds, or in any build where the
dcheck_always_on=true GN argument is being used. In fact, at any time during development (including Release builds), it is highly recommended to use
dcheck_always_on=true to catch bugs.
When OSP_DCHECKs are “turned off” they effectively become code comments: All supported compilers will not generate any code, and they will automatically strip-out unused functions and constants referenced in OSP_DCHECK expressions (unless they are “extern” to the local module); and so there is absolutely no run-time/space overhead when the program runs. For this reason, a developer need not explicitly sprinkle “#if OSP_DCHECK_IS_ON()” guards all around any functions, variables, etc. that will be unused in “DCHECK off” builds.
Use OSP_DCHECK and OSP_CHECK in accordance with the Chromium guidance for DCHECK/CHECK.