For other languages, please see the Chromium style guides.
Chromium follows the Google C++ Style Guide unless an exception is listed below.
A checkout should give you clang-format to automatically format C++ code. By policy, Clang's formatting of code should always be accepted in code reviews.
You can propose changes to this style guide by sending an email to cxx@chromium.org
. Ideally, the list will arrive at some consensus and you can request review for a change to this file. If there's no consensus, src/styleguide/c++/OWNERS
get to decide.
Blink code in third_party/blink
uses Blink style.
Google and Chromium style targets C++20. Additionally, some features of supported C++ versions remain forbidden. The status of Chromium's C++ support is covered in more detail in Modern C++ use in Chromium.
ForTesting
is the conventional suffix although similar patterns, such as ForTest
, are also accepted. These suffixes are checked at presubmit time to ensure the functions are called only by test files. In the rare case of adding a test-only code path to an area where a testing suffix is not possible, CHECK_IS_TEST() may be appropriate.testonly=true
. Tests can depend on such targets, but production code can not.testonly
targets should be placed in a test/
subdirectory. For example, see //mojo/core/core_unittest.cc
and //mojo/core/test/mojo_test_base.cc
. For test classes used across multiple directories, it might make sense to move them into a nested test
namespace for clarity._unittest.cc
suffix for unit test files, in Chromium we still use this suffix to distinguish unit tests from browser tests, which are written in files with the _browsertest.cc
suffix.*
and &
by the type rather than the variable name.(foo == 0)
to (0 == foo)
.{}
on all conditionals/loops.Items local to a .cc file should be wrapped in an unnamed namespace. While some such items are already file-scope by default in C++, not all are; also, shared objects on Linux builds export all symbols, so unnamed namespaces (which restrict these symbols to the compilation unit) improve function call cost and reduce the size of entry point tables.
Symbols can be exported (made visible outside of a shared library/DLL) by annotating with a <COMPONENT>_EXPORT
macro name (where <COMPONENT>
is the name of the component being built, e.g. BASE, NET, CONTENT, etc.). Class annotations should precede the class name:
class FOO_EXPORT Foo { void Bar(); void Baz(); // ... };
Function annotations should precede the return type:
class FooSingleton { FOO_EXPORT Foo& GetFoo(); FOO_EXPORT Foo& SetFooForTesting(Foo* foo); void SetFoo(Foo* foo); // Not exported. };
Multiple inheritance and virtual inheritance are permitted in Chromium code, but discouraged (beyond the “interface” style of inheritance allowed by the Google style guide, for which we do not require classes to have the “Interface” suffix). Consider whether composition could solve the problem instead.
Simple accessors should generally be the only inline functions. These should be named using snake_case()
. Virtual functions should never be declared this way.
Remove all logging before checking in code. The exception is temporary logging to track down a specific bug. This should be a rare exception, and you should have a plan for how to manually collect/use the logged data. Afterwards you should remove the logging. Note that logs are not present in crashes. Use base::debug::ScopedCrashKeyString
(link) for that.
For the rare case when logging needs to stay in the codebase for a while, prefer DVLOG(1)
to other logging methods. This avoids bloating the release executable and in debug can be selectively enabled at runtime by command-line arguments:
--v=n
sets the global log level to n (default 0). All log statements with a log level less than or equal to the global level will be printed.--vmodule=mod=n[,mod=n,...]
overrides the global log level for the module mod. Supplying the string foo for mod will affect all files named foo.cc, while supplying a wildcard like *bar/baz*
will affect all files with bar/baz
in their full pathnames.Rationale:
To #ifdef
code for specific platforms, use the macros defined in build/build_config.h
and in the Chromium build config files, not other macros set by specific compilers or build environments (e.g. WIN32
).
Place platform-specific #includes in their own section below the “normal” #includes
. Repeat the standard #include
order within this section:
#include "foo/foo.h" #include <stdint.h> #include <algorithm> #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/common/render_messages.h" #if BUILDFLAG(IS_WIN) #include <windows.h> #include "base/win/com_init_util.h" #elif BUILDFLAG(IS_POSIX) #include "base/posix/global_descriptors.h" #endif
int
and size_t
.size_t
for object and allocation sizes, object counts, array and pointer offsets, vector indices, and so on. This prevents casts when dealing with STL APIs, and if followed consistently across the codebase, minimizes casts elsewhere.size_t
for one of these concepts, e.g. as a storage space optimization. In these cases, continue to use size_t
in public-facing function declarations, and continue to use unsigned types internally (e.g. uint32_t
).checked_cast<T>
(from base/numerics/safe_conversions.h
) when you need to CHECK
that the source value is in range for the destination type. Use saturated_cast<T>
if you instead wish to clamp out-of-range values. CheckedNumeric
is an ergonomic way to perform safe arithmetic and casting in many cases.std::u16string
and char16_t*
for 16-bit strings, u"..."
to declare UTF-16 literals, and either the actual characters or the \uXXXX
or \UXXXXXXXX
escapes for Unicode characters. Avoid \xXX...
-style escapes, which can cause subtle problems if someone attempts to change the type of string that holds the literal. In code used only on Windows, it may be necessary to use std::wstring
and wchar_t*
; these are legal, but note that they are distinct types and are often not 16-bit on other platforms.When functions need to take raw or smart pointers as parameters, use the following conventions. Here we refer to the parameter type as T
and name as t
.
t
's ownership, declare the param as T*
. The caller is expected to ensure t
stays alive as long as necessary, generally through the duration of the call. Exception: In rare cases (e.g. using lambdas with STL algorithms over containers of unique_ptr<>
s), you may be forced to declare the param as const std::unique_ptr<T>&
. Do this only when required.std::unique_ptr<T>
.scoped_refptr<T>
. The caller can decide whether it wishes to transfer ownership (by calling std::move(t)
when passing t
) or retain its ref (by simply passing t directly).Conventions for return values are similar with an important distinction:
std::unique_ptr<T>
or scoped_refptr<T>
by value when the impl is handing off ownership.const scoped_refptr<T>&
when the impl retains ownership so the caller isn‘t required to take a ref: this avoids bumping the reference count if the caller doesn’t need ownership and also helps binary size).A great deal of Chromium code predates the above rules. In particular, some functions take ownership of params passed as T*
, or take const scoped_refptr<T>&
instead of T*
, or return T*
instead of scoped_refptr<T>
(to avoid refcount churn pre-C++11). Try to clean up such code when you find it, or at least not make such usage any more widespread.
Use const raw_ref<T>
or raw_ptr<T>
for class and struct fields in place of a raw C++ reference T&
or pointer T*
whenever possible, except in paths that include /renderer/
or blink/public/web/
. These are non-owning smart pointers that have improved memory-safety over raw pointers and references, and can prevent exploitation of a significant percentage of Use-after-Free bugs.
Prefer const raw_ref<T>
whenever the held pointer will never be null, and it's ok to drop the const
if the internal reference can be reassigned to point to a different T
. Use raw_ptr<T>
in order to express that the pointer can be null. Only raw_ptr<T>
can be default-constructed, since raw_ref<T>
disallows nullness.
Using raw_ref<T>
or raw_ptr<T>
may not be possible in rare cases for performance reasons. Additionally, raw_ptr<T>
doesn’t support some C++ scenarios (e.g. constexpr
, ObjC pointers). Tooling will help to encourage use of these types in the future. See raw_ptr.md for how to add exclusions.
Much code in Chrome needs to be “sequence-aware” rather than “thread-aware”. If you need a sequence-local variable, see base::SequenceLocalStorageSlot
.
If you truly need a thread-local variable, then you can use a thread_local
, as long as it complies with the following requirements:
std::is_trivially_destructible_v<T>
, due to past problems with “spooky action at a distance” during destruction. Note that raw_ptr<T>
is not a trivially-destructible type and may not be contained in thread_locals
.COMPONENT_EXPORT
), since this may result in codegen bugs on Mac; and at least on Windows, this probably won't compile in the component build anyway. As a workaround, create an exported getter function that creates a thread_local
internally and returns a ref to it.ABSL_CONST_INIT
, as specified in the Google C++ Style Guide.If you can't comply with these requirements, consider base::ThreadLocalOwnedPointer
or another nearby low-level utility.
Unlike the Google style guide, Chromium style prefers forward declarations to #includes
where possible. This can reduce compile times and result in fewer files needing recompilation when a header changes.
You can and should use forward declarations for most types passed or returned by value, reference, or pointer, or types stored as pointer members or in most STL containers. However, if it would otherwise make sense to use a type as a member by-value, don't convert it to a pointer just to be able to forward-declare the type.
All files in Chromium start with a common license header. That header should look like this:
// Copyright $YEAR The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
Some important notes about this header:
$YEAR
should be set to the current year at the time a file is created, and not changed thereafter.Use standard #include
guards in all header files (see the Google style guide sections on these for the naming convention). Do not use #pragma once
; historically it was not supported on all platforms, and it does not seem to outperform #include guards even on platforms which do support it.
Use the CHECK()
family of macros to both document and verify invariants.
DCHECK()
. Do not do this unless necessary.CHECK()
s hit stable, and failure doesn't obviously result in a crash or security risk, you may use CHECK(Foo(), base::NotFatalUntil::M120)
with a future milestone to gather non-fatal diagnostics in stable before automatically turning fatal in a later milestone.DCHECK()
in most cases, so a great deal of existing code uses DCHECK()
instead of CHECK()
. You are encouraged to migrate to CHECK()
s with a trailing base::NotFatalUntil::M120
argument, as there's stability risk given the under-tested invariant, or add a comment explaining why DCHECK is appropriate given the current guidance.Use NOTREACHED_NORETURN()
to indicate a piece of code is unreachable. Control flow does not leave this call, so there should be no executable statements after it (even return statements from non-void functions). The compiler will issue dead-code warnings.
CHECK()
instead of conditionally hitting a NOTREACHED[_NORETURN]()
, where feasible.NOTREACHED_NORETURN()
s hit stable, and failure doesn't obviously result in a crash or security risk, you may use NOTREACHED( base::NotFatalUntil::M120)
with a future milestone to gather non-fatal diagnostics in stable before automatically turning fatal in a later milestone.NOTREACHED()
for this purpose. Migrating this code to be fatal (and [[noreturn]]
) is part of a kNotReachedIsFatal
experiment.Use base::ImmediateCrash()
in the rare case where it's necessary to terminate the current process for reasons outside its control, that are not violations of our invariants.
Use base::debug::DumpWithoutCrashing()
to generate a crash report but keep running in the case where you are investigating some failure but know that it's safe to continue execution.
Use DLOG(FATAL)
(does nothing in production) or LOG(DFATAL)
(logs an error and continues running in production) if you need to log an error in tests from production code. From test code, use ADD_FAILURE()
directly. Do not use these for invariant failures. Those should use CHECK()
or NOTREACHED_NORETURN()
as noted above.
For more details, see checks.md.
Try to avoid test-only code paths in production code. Such code paths make production code behave differently in tests. This makes both tests and production code hard to reason about. Consider dependency injection, fake classes, etc to avoid such code paths.
However, if a test-only path in production code cannot be avoided, instrument that code path with CHECK_IS_TEST();
to assert that the code is only run in tests.
// `profile_manager` may not be available in tests. if (!profile_manager) { CHECK_IS_TEST(); return std::string(); }
CHECK_IS_TEST();
will crash outside of tests. This asserts that the test-only code path is not accidentally or maliciously taken in production.