docs/14_Others/代码实践/apollo_best_coding_practice.md
Always build, test, and lint all.
./apollo.sh check
Always write unit tests and put them along with the source files.
foobar.h
foobar.cc
foobar_test.cc
A Bazel target should contain at most one header and one source file.
cc_library(
name = "foobar",
hdrs = ["foobar.h"],
srcs = ["foobar.cc"],
deps = [
...
],
)
cc_test(
name = "foobar_test",
srcs = ["foobar_test.cc"],
deps = [
":foobar",
...
]
)
You can use ./apollo.sh format <path/to/BUILD> to fix BUILD file style
issues.
In general, Apollo follows
Google C++ coding style.
You should run scripts/clang_format.sh <path/to/cpp/dirs/or/files> or
./apollo.sh format -c <path/to/cpp/dirs/or/files> to fix C++ style issues.
Simple and unified function signature.
// 1. For input objects, const reference guarantes that it is valid, while
// pointers might be NULL or wild. Don't give others the chance to break
// you.
// 2. For input scalars, just pass by value, which gives better locality and
// thus performance.
// 3. For output, it's the caller's responsibility to make sure the pointer
// is valid. No need to do sanity check or mark it as "OutputType* const",
// as pointer redirection is never allowed.
void FooBar(const InputObjectType& input1, const InputScalaType input2, ...,
OutputType* output1, ...);
// RVO machanism will help you avoid unnecessary object copy.
// See https://en.wikipedia.org/wiki/Copy_elision#Return_value_optimization
OutputType FooBar(const InputType& input);
Use const whenever possible.
// Variables that don't change.
const size_t current_size = vec.size();
// Functions that have no side effect.
const std::string& name() const;
Prefer C++ headers over C headers.
We prefer using #include <ctime> over #include <time.h>, <cmath> over
<math.h>, <cstdio> over <stdio.h>, <cstring> over <string.h>, etc.
Include necessary headers only. No more, no less.
Please also pay attention to header orders. Again, you can use
apollo.sh format -c or scripts/clang_format.sh to fix header order
issues.
List only direct dependencies in deps section of a Bazel target.
Generally, only targets to which the included headers belongs should be listed as a dependency.
For example, suppose sandwich.h includes bread.h which in turn includes
flour.h. Since sandwich.h doesn't include flour.h directly (who wants
flour in their sandwich?), the BUILD file would look like this:
cc_library(
name = "sandwich",
srcs = ["sandwich.cc"],
hdrs = ["sandwich.h"],
deps = [
":bread",
# BAD practice to uncomment the line below
# ":flour",
],
)
cc_library(
name = "bread",
srcs = ["bread.cc"],
hdrs = ["bread.h"],
deps = [":flour"],
)
cc_library(
name = "flour",
srcs = ["flour.cc"],
hdrs = ["flour.h"],
)
Conform to the DRY principle.
Don't repeat yourself, in any way. Avoid duplicate classes, functions, const variables, or a simple piece of code. Some examples:
apollo::common::util::Type, but better to make a short alias if you need
to use twice or more: using apollo::common::util::Type;.a_proto.field_1().field_2().field_3(), but better to save the reference
of a common part first if you need to access it twice or more:
const auto& field_2 = a_proto.field_1().field_2();.